@applemusic-like-lyrics/core 0.5.0 → 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.
- package/dist/amll-core.cjs +458 -270
- package/dist/amll-core.cjs.map +1 -1
- package/dist/amll-core.d.cts +140 -81
- package/dist/amll-core.d.mts +140 -81
- package/dist/amll-core.mjs +458 -270
- package/dist/amll-core.mjs.map +1 -1
- package/dist/style.css +148 -80
- package/package.json +4 -4
package/dist/amll-core.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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;
|
|
@@ -1706,8 +1717,11 @@ var BackgroundRender = class BackgroundRender {
|
|
|
1706
1717
|
//#region src/styles/lyric-player.module.css
|
|
1707
1718
|
var lyric_player_module_default = {
|
|
1708
1719
|
"active": "FmKaba_active",
|
|
1720
|
+
"bgWrapper": "FmKaba_bgWrapper",
|
|
1721
|
+
"bgWrapperActive": "FmKaba_bgWrapperActive",
|
|
1722
|
+
"bgWrapperHidden": "FmKaba_bgWrapperHidden",
|
|
1723
|
+
"bgWrapperTop": "FmKaba_bgWrapperTop",
|
|
1709
1724
|
"bottomLine": "FmKaba_bottomLine",
|
|
1710
|
-
"dirty": "FmKaba_dirty",
|
|
1711
1725
|
"disableSpring": "FmKaba_disableSpring",
|
|
1712
1726
|
"duet": "FmKaba_duet",
|
|
1713
1727
|
"emphasize": "FmKaba_emphasize",
|
|
@@ -1718,8 +1732,10 @@ var lyric_player_module_default = {
|
|
|
1718
1732
|
"lyricBgLine": "FmKaba_lyricBgLine",
|
|
1719
1733
|
"lyricDuetLine": "FmKaba_lyricDuetLine",
|
|
1720
1734
|
"lyricLine": "FmKaba_lyricLine",
|
|
1735
|
+
"lyricLineWrapper": "FmKaba_lyricLineWrapper",
|
|
1721
1736
|
"lyricMainLine": "FmKaba_lyricMainLine",
|
|
1722
1737
|
"lyricSubLine": "FmKaba_lyricSubLine",
|
|
1738
|
+
"playing": "FmKaba_playing",
|
|
1723
1739
|
"romanWord": "FmKaba_romanWord",
|
|
1724
1740
|
"rubyWord": "FmKaba_rubyWord",
|
|
1725
1741
|
"tmpDisableTransition": "FmKaba_tmpDisableTransition",
|
|
@@ -1820,27 +1836,31 @@ function cleanUnintentionalOverlaps(lines) {
|
|
|
1820
1836
|
* 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试最多提前 400ms 或上一行时长的 30%
|
|
1821
1837
|
*/
|
|
1822
1838
|
function tryAdvanceStartTime(lines) {
|
|
1823
|
-
|
|
1839
|
+
const defaultAdvanceAmount = 600;
|
|
1840
|
+
const fallbackAdvanceAmount = 400;
|
|
1841
|
+
const fallbackAdvanceRatio = .3;
|
|
1842
|
+
let prevLineStartTime = 0;
|
|
1843
|
+
let prevLineEndTime = 0;
|
|
1844
|
+
let prevMainGroupStartTime = 0;
|
|
1845
|
+
let prevMainGroupEndTime = 0;
|
|
1846
|
+
let hasPrevLine = false;
|
|
1847
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1824
1848
|
const line = lines[i];
|
|
1825
1849
|
if (line.isBG) continue;
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
let prevIdx = i - 1;
|
|
1829
|
-
if (lines[prevIdx].isBG) prevIdx--;
|
|
1830
|
-
if (prevIdx >= 0) prevLine = lines[prevIdx];
|
|
1831
|
-
}
|
|
1850
|
+
const originalStartTime = line.startTime;
|
|
1851
|
+
const originalEndTime = line.endTime;
|
|
1832
1852
|
let targetAdvanceAmount = 0;
|
|
1833
1853
|
let safeBoundary = 0;
|
|
1834
|
-
if (
|
|
1835
|
-
targetAdvanceAmount =
|
|
1836
|
-
safeBoundary =
|
|
1854
|
+
if (hasPrevLine) if (originalStartTime >= prevLineEndTime) {
|
|
1855
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1856
|
+
safeBoundary = prevMainGroupEndTime;
|
|
1837
1857
|
} else {
|
|
1838
|
-
targetAdvanceAmount =
|
|
1839
|
-
const prevDuration =
|
|
1840
|
-
safeBoundary =
|
|
1858
|
+
targetAdvanceAmount = fallbackAdvanceAmount;
|
|
1859
|
+
const prevDuration = prevLineEndTime - prevLineStartTime;
|
|
1860
|
+
safeBoundary = prevLineStartTime + prevDuration * fallbackAdvanceRatio;
|
|
1841
1861
|
}
|
|
1842
1862
|
else {
|
|
1843
|
-
targetAdvanceAmount =
|
|
1863
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1844
1864
|
safeBoundary = 0;
|
|
1845
1865
|
}
|
|
1846
1866
|
const targetTime = line.startTime - targetAdvanceAmount;
|
|
@@ -1848,6 +1868,20 @@ function tryAdvanceStartTime(lines) {
|
|
|
1848
1868
|
if (newStartTime < line.startTime) line.startTime = newStartTime;
|
|
1849
1869
|
const nextLine = lines[i + 1];
|
|
1850
1870
|
if (nextLine?.isBG) nextLine.startTime = line.startTime;
|
|
1871
|
+
if (hasPrevLine) if (originalStartTime < prevMainGroupEndTime && originalEndTime > prevMainGroupStartTime) {
|
|
1872
|
+
prevMainGroupStartTime = Math.min(prevMainGroupStartTime, originalStartTime);
|
|
1873
|
+
prevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);
|
|
1874
|
+
} else {
|
|
1875
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1876
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1877
|
+
}
|
|
1878
|
+
else {
|
|
1879
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1880
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1881
|
+
}
|
|
1882
|
+
prevLineStartTime = originalStartTime;
|
|
1883
|
+
prevLineEndTime = originalEndTime;
|
|
1884
|
+
hasPrevLine = true;
|
|
1851
1885
|
}
|
|
1852
1886
|
}
|
|
1853
1887
|
/**
|
|
@@ -2125,6 +2159,7 @@ function solveSpring(from, velocity, to, delay = 0, params) {
|
|
|
2125
2159
|
//#endregion
|
|
2126
2160
|
//#region src/lyric-player/base/bottom-line.ts
|
|
2127
2161
|
var BottomLineEl = class {
|
|
2162
|
+
lyricPlayer;
|
|
2128
2163
|
element = document.createElement("div");
|
|
2129
2164
|
left = 0;
|
|
2130
2165
|
top = 0;
|
|
@@ -2247,19 +2282,19 @@ const LayoutAlignAnchor = {
|
|
|
2247
2282
|
function computeCurrentInterlude(input) {
|
|
2248
2283
|
const currentTime = input.currentTime + 20;
|
|
2249
2284
|
const currentIndex = input.scrollToIndex;
|
|
2250
|
-
const
|
|
2285
|
+
const groups = input.currentGroups;
|
|
2251
2286
|
const checkGap = (k) => {
|
|
2252
|
-
if (k < -1 || k >=
|
|
2253
|
-
const
|
|
2254
|
-
const
|
|
2255
|
-
const gapStart =
|
|
2256
|
-
const gapEnd = Math.max(gapStart,
|
|
2257
|
-
if (gapEnd - gapStart < 4e3) return;
|
|
2287
|
+
if (k < -1 || k >= groups.length - 1) return void 0;
|
|
2288
|
+
const prevGroup = k === -1 ? null : groups[k];
|
|
2289
|
+
const nextGroup = groups[k + 1];
|
|
2290
|
+
const gapStart = prevGroup ? prevGroup.endTime : 0;
|
|
2291
|
+
const gapEnd = Math.max(gapStart, nextGroup.startTime - 250);
|
|
2292
|
+
if (gapEnd - gapStart < 4e3) return void 0;
|
|
2258
2293
|
if (gapEnd > currentTime && gapStart < currentTime) return {
|
|
2259
2294
|
startTime: Math.max(gapStart, currentTime),
|
|
2260
2295
|
endTime: gapEnd,
|
|
2261
2296
|
anchorLineIndex: k,
|
|
2262
|
-
isNextDuet:
|
|
2297
|
+
isNextDuet: nextGroup.mainLine.getLine().isDuet
|
|
2263
2298
|
};
|
|
2264
2299
|
};
|
|
2265
2300
|
return checkGap(currentIndex - 1) || checkGap(currentIndex) || checkGap(currentIndex + 1);
|
|
@@ -2272,8 +2307,8 @@ function computeCurrentInterlude(input) {
|
|
|
2272
2307
|
* - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping
|
|
2273
2308
|
*/
|
|
2274
2309
|
function computeLinePosYSpringParams(input) {
|
|
2275
|
-
const { enabled,
|
|
2276
|
-
if (!enabled ||
|
|
2310
|
+
const { enabled, currentGroups, scrollToIndex, isSeeking, isInterludeActive } = input;
|
|
2311
|
+
if (!enabled || currentGroups.length === 0) return { shouldUpdate: false };
|
|
2277
2312
|
if (isSeeking || isInterludeActive) return {
|
|
2278
2313
|
shouldUpdate: true,
|
|
2279
2314
|
params: {
|
|
@@ -2281,10 +2316,10 @@ function computeLinePosYSpringParams(input) {
|
|
|
2281
2316
|
damping: 15
|
|
2282
2317
|
}
|
|
2283
2318
|
};
|
|
2284
|
-
const
|
|
2285
|
-
const
|
|
2286
|
-
if (!
|
|
2287
|
-
const interval =
|
|
2319
|
+
const currentGroup = currentGroups[scrollToIndex];
|
|
2320
|
+
const prevGroup = currentGroups[scrollToIndex - 1];
|
|
2321
|
+
if (!currentGroup || !prevGroup) return { shouldUpdate: false };
|
|
2322
|
+
const interval = currentGroup.startTime - prevGroup.startTime;
|
|
2288
2323
|
const MIN_INTERVAL = 100;
|
|
2289
2324
|
const MAX_INTERVAL = 800;
|
|
2290
2325
|
const clampedInterval = clamp(interval, MIN_INTERVAL, MAX_INTERVAL);
|
|
@@ -2302,38 +2337,33 @@ function computeLinePosYSpringParams(input) {
|
|
|
2302
2337
|
};
|
|
2303
2338
|
}
|
|
2304
2339
|
/**
|
|
2305
|
-
*
|
|
2340
|
+
* 计算一组歌词在当前布局中的视觉呈现参数。
|
|
2306
2341
|
*
|
|
2307
2342
|
* 根据播放状态、缓冲状态、布局模式与间奏信息,
|
|
2308
|
-
*
|
|
2343
|
+
* 生成一组歌词最终应使用的活跃状态、不透明度与模糊值。
|
|
2309
2344
|
*/
|
|
2310
|
-
function
|
|
2311
|
-
const {
|
|
2312
|
-
const isActive = hasBuffered ||
|
|
2345
|
+
function computeGroupPresentation(input) {
|
|
2346
|
+
const { groupIndex, scrollToIndex, latestIndex, hasBuffered, hidePassedLines, isPlaying, isNonDynamic, enableBlur, isUserScrolling, isCompact, interlude } = input;
|
|
2347
|
+
const isActive = hasBuffered || groupIndex >= scrollToIndex && groupIndex < latestIndex;
|
|
2313
2348
|
const blurLevel = computeLineBlur({
|
|
2314
2349
|
enableBlur,
|
|
2315
2350
|
isUserScrolling,
|
|
2316
2351
|
isActive,
|
|
2317
|
-
itemIndex:
|
|
2352
|
+
itemIndex: groupIndex,
|
|
2318
2353
|
scrollToIndex,
|
|
2319
2354
|
latestIndex,
|
|
2320
2355
|
isCompact
|
|
2321
2356
|
});
|
|
2322
2357
|
let targetOpacity;
|
|
2323
|
-
if (hidePassedLines) if (
|
|
2358
|
+
if (hidePassedLines) if (groupIndex < (interlude ? interlude.anchorLineIndex + 1 : scrollToIndex) && isPlaying) targetOpacity = 1e-4;
|
|
2324
2359
|
else if (hasBuffered) targetOpacity = .85;
|
|
2325
2360
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2326
2361
|
else if (hasBuffered) targetOpacity = .85;
|
|
2327
2362
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2328
|
-
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
2329
|
-
let targetScale = 100;
|
|
2330
|
-
if (!isActive && isPlaying) targetScale = line.isBG ? 75 : SCALE_ASPECT;
|
|
2331
2363
|
return {
|
|
2332
2364
|
isActive,
|
|
2333
2365
|
targetOpacity,
|
|
2334
|
-
|
|
2335
|
-
blurLevel,
|
|
2336
|
-
renderMode: isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID
|
|
2366
|
+
blurLevel
|
|
2337
2367
|
};
|
|
2338
2368
|
}
|
|
2339
2369
|
/**
|
|
@@ -2489,50 +2519,29 @@ const eqSet = (xs, ys) => xs.size === ys.size && [...xs].every((x) => ys.has(x))
|
|
|
2489
2519
|
* - 根据新的热行状态和已有的缓冲行状态,计算出应移除的缓冲行 ID
|
|
2490
2520
|
*/
|
|
2491
2521
|
function computePlayerTimeState(input) {
|
|
2492
|
-
const { time,
|
|
2493
|
-
const
|
|
2522
|
+
const { time, currentGroups, timelineState: { hotGroups, bufferedGroups } } = input;
|
|
2523
|
+
const nextHotGroups = new Set(hotGroups);
|
|
2494
2524
|
const addedIds = /* @__PURE__ */ new Set();
|
|
2495
2525
|
const removedHotIds = /* @__PURE__ */ new Set();
|
|
2496
2526
|
const removedBufferedIds = /* @__PURE__ */ new Set();
|
|
2497
|
-
for (const lastHotId of
|
|
2498
|
-
const
|
|
2499
|
-
if (!
|
|
2500
|
-
|
|
2501
|
-
removedHotIds.add(lastHotId);
|
|
2502
|
-
continue;
|
|
2503
|
-
}
|
|
2504
|
-
if (line.isBG) continue;
|
|
2505
|
-
const nextLine = processedLines[lastHotId + 1];
|
|
2506
|
-
if (nextLine?.isBG) {
|
|
2507
|
-
const nextMainLine = processedLines[lastHotId + 2];
|
|
2508
|
-
const startTime = Math.min(line.startTime, nextLine.startTime);
|
|
2509
|
-
const endTime = Math.min(Math.max(line.endTime, nextMainLine?.startTime ?? Number.MAX_VALUE), Math.max(line.endTime, nextLine.endTime));
|
|
2510
|
-
if (time < startTime || endTime <= time) {
|
|
2511
|
-
nextHotLines.delete(lastHotId);
|
|
2512
|
-
removedHotIds.add(lastHotId);
|
|
2513
|
-
nextHotLines.delete(lastHotId + 1);
|
|
2514
|
-
removedHotIds.add(lastHotId + 1);
|
|
2515
|
-
}
|
|
2516
|
-
} else if (time < line.startTime || line.endTime <= time) {
|
|
2517
|
-
nextHotLines.delete(lastHotId);
|
|
2527
|
+
for (const lastHotId of hotGroups) {
|
|
2528
|
+
const group = currentGroups[lastHotId];
|
|
2529
|
+
if (!group || time < group.startTime || group.endTime <= time) {
|
|
2530
|
+
nextHotGroups.delete(lastHotId);
|
|
2518
2531
|
removedHotIds.add(lastHotId);
|
|
2519
2532
|
}
|
|
2520
2533
|
}
|
|
2521
|
-
for (let id = 0; id <
|
|
2522
|
-
const
|
|
2523
|
-
if (!
|
|
2524
|
-
if (
|
|
2525
|
-
|
|
2534
|
+
for (let id = 0; id < currentGroups.length; id++) {
|
|
2535
|
+
const group = currentGroups[id];
|
|
2536
|
+
if (!group) continue;
|
|
2537
|
+
if (group.startTime <= time && group.endTime > time && !nextHotGroups.has(id)) {
|
|
2538
|
+
nextHotGroups.add(id);
|
|
2526
2539
|
addedIds.add(id);
|
|
2527
|
-
if (processedLines[id + 1]?.isBG) {
|
|
2528
|
-
nextHotLines.add(id + 1);
|
|
2529
|
-
addedIds.add(id + 1);
|
|
2530
|
-
}
|
|
2531
2540
|
}
|
|
2532
2541
|
}
|
|
2533
|
-
for (const id of
|
|
2542
|
+
for (const id of bufferedGroups) if (!nextHotGroups.has(id)) removedBufferedIds.add(id);
|
|
2534
2543
|
return {
|
|
2535
|
-
|
|
2544
|
+
nextHotGroups,
|
|
2536
2545
|
addedIds,
|
|
2537
2546
|
removedHotIds,
|
|
2538
2547
|
removedBufferedIds
|
|
@@ -2544,10 +2553,10 @@ function computePlayerTimeState(input) {
|
|
|
2544
2553
|
* 若当前仍存在缓冲行,则优先对齐到最靠前的缓冲行;
|
|
2545
2554
|
* 否则对齐到第一条开始时间不小于当前时间的歌词行。
|
|
2546
2555
|
*/
|
|
2547
|
-
function pickScrollToIndexForSeek(time,
|
|
2548
|
-
if (
|
|
2549
|
-
const foundIndex =
|
|
2550
|
-
return foundIndex === -1 ?
|
|
2556
|
+
function pickScrollToIndexForSeek(time, currentGroups, bufferedGroups) {
|
|
2557
|
+
if (bufferedGroups.size > 0) return Math.min(...bufferedGroups);
|
|
2558
|
+
const foundIndex = currentGroups.findIndex((group) => group.startTime >= time);
|
|
2559
|
+
return foundIndex === -1 ? currentGroups.length : foundIndex;
|
|
2551
2560
|
}
|
|
2552
2561
|
/**
|
|
2553
2562
|
* 提交时间线状态转移的纯函数。
|
|
@@ -2557,45 +2566,45 @@ function pickScrollToIndexForSeek(time, processedLines, bufferedLines) {
|
|
|
2557
2566
|
* 是否需要重置用户滚动状态、是否需要触发布局。
|
|
2558
2567
|
*/
|
|
2559
2568
|
function commitPlayerTimeState(input) {
|
|
2560
|
-
const { timelineState, time,
|
|
2569
|
+
const { timelineState, time, currentGroups, hasBottomContent, stateResult } = input;
|
|
2561
2570
|
const { addedIds, removedHotIds, removedBufferedIds } = stateResult;
|
|
2562
2571
|
const { isSeeking } = timelineState;
|
|
2563
2572
|
timelineState.currentTime = time;
|
|
2564
|
-
timelineState.
|
|
2573
|
+
timelineState.hotGroups = stateResult.nextHotGroups;
|
|
2565
2574
|
let shouldLayout = false;
|
|
2566
2575
|
let shouldResetScroll = false;
|
|
2567
|
-
const
|
|
2568
|
-
const
|
|
2576
|
+
const groupsToEnable = [];
|
|
2577
|
+
const groupsToDisable = /* @__PURE__ */ new Set();
|
|
2569
2578
|
if (isSeeking) {
|
|
2570
|
-
timelineState.
|
|
2571
|
-
timelineState.scrollToIndex = pickScrollToIndexForSeek(time,
|
|
2572
|
-
for (const id of removedHotIds)
|
|
2573
|
-
for (const id of timelineState.
|
|
2574
|
-
for (const id of removedBufferedIds)
|
|
2579
|
+
timelineState.bufferedGroups = new Set([...timelineState.hotGroups]);
|
|
2580
|
+
timelineState.scrollToIndex = pickScrollToIndexForSeek(time, currentGroups, timelineState.bufferedGroups);
|
|
2581
|
+
for (const id of removedHotIds) groupsToDisable.add(id);
|
|
2582
|
+
for (const id of timelineState.hotGroups) groupsToEnable.push(id);
|
|
2583
|
+
for (const id of removedBufferedIds) groupsToDisable.add(id);
|
|
2575
2584
|
shouldResetScroll = true;
|
|
2576
2585
|
shouldLayout = true;
|
|
2577
2586
|
} else if (addedIds.size > 0) {
|
|
2578
2587
|
for (const id of addedIds) {
|
|
2579
|
-
timelineState.
|
|
2580
|
-
|
|
2588
|
+
timelineState.bufferedGroups.add(id);
|
|
2589
|
+
groupsToEnable.push(id);
|
|
2581
2590
|
}
|
|
2582
2591
|
for (const id of removedBufferedIds) {
|
|
2583
|
-
timelineState.
|
|
2584
|
-
|
|
2592
|
+
timelineState.bufferedGroups.delete(id);
|
|
2593
|
+
groupsToDisable.add(id);
|
|
2585
2594
|
}
|
|
2586
|
-
if (timelineState.
|
|
2595
|
+
if (timelineState.bufferedGroups.size > 0) timelineState.scrollToIndex = Math.min(...timelineState.bufferedGroups);
|
|
2587
2596
|
shouldLayout = true;
|
|
2588
|
-
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.
|
|
2589
|
-
for (const id of timelineState.
|
|
2590
|
-
if (timelineState.
|
|
2591
|
-
timelineState.
|
|
2592
|
-
|
|
2597
|
+
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.bufferedGroups)) {
|
|
2598
|
+
for (const id of timelineState.bufferedGroups) {
|
|
2599
|
+
if (timelineState.hotGroups.has(id)) continue;
|
|
2600
|
+
timelineState.bufferedGroups.delete(id);
|
|
2601
|
+
groupsToDisable.add(id);
|
|
2593
2602
|
}
|
|
2594
2603
|
shouldLayout = true;
|
|
2595
2604
|
}
|
|
2596
|
-
if (timelineState.
|
|
2597
|
-
if (time >=
|
|
2598
|
-
const targetIndex = hasBottomContent ?
|
|
2605
|
+
if (timelineState.bufferedGroups.size === 0 && currentGroups.length > 0) {
|
|
2606
|
+
if (time >= currentGroups[currentGroups.length - 1].endTime) {
|
|
2607
|
+
const targetIndex = hasBottomContent ? currentGroups.length : currentGroups.length - 1;
|
|
2599
2608
|
if (timelineState.scrollToIndex !== targetIndex) {
|
|
2600
2609
|
timelineState.scrollToIndex = targetIndex;
|
|
2601
2610
|
shouldLayout = true;
|
|
@@ -2606,8 +2615,8 @@ function commitPlayerTimeState(input) {
|
|
|
2606
2615
|
return {
|
|
2607
2616
|
shouldLayout,
|
|
2608
2617
|
shouldResetScroll,
|
|
2609
|
-
|
|
2610
|
-
|
|
2618
|
+
groupsToEnable,
|
|
2619
|
+
groupsToDisable: [...groupsToDisable]
|
|
2611
2620
|
};
|
|
2612
2621
|
}
|
|
2613
2622
|
//#endregion
|
|
@@ -2622,17 +2631,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2622
2631
|
timelineState = {
|
|
2623
2632
|
currentTime: 0,
|
|
2624
2633
|
lastCurrentTime: 0,
|
|
2625
|
-
|
|
2626
|
-
|
|
2634
|
+
hotGroups: /* @__PURE__ */ new Set(),
|
|
2635
|
+
bufferedGroups: /* @__PURE__ */ new Set(),
|
|
2627
2636
|
scrollToIndex: 0,
|
|
2628
2637
|
isSeeking: false,
|
|
2629
2638
|
isPlaying: true,
|
|
2630
2639
|
initialLayoutFinished: false
|
|
2631
2640
|
};
|
|
2632
2641
|
/** @internal */
|
|
2633
|
-
|
|
2634
|
-
/** @internal */
|
|
2635
|
-
lyricLineElementMap = /* @__PURE__ */ new WeakMap();
|
|
2642
|
+
lyricGroupElementMap = /* @__PURE__ */ new WeakMap();
|
|
2636
2643
|
currentLyricLines = [];
|
|
2637
2644
|
processedLines = [];
|
|
2638
2645
|
lyricLinesIndexes = /* @__PURE__ */ new WeakMap();
|
|
@@ -2664,10 +2671,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2664
2671
|
isScrolled: false,
|
|
2665
2672
|
isUserScrolling: false
|
|
2666
2673
|
};
|
|
2667
|
-
|
|
2674
|
+
currentLyricGroups = [];
|
|
2675
|
+
lyricGroupSize = /* @__PURE__ */ new WeakMap();
|
|
2668
2676
|
size = [0, 0];
|
|
2669
2677
|
isPageVisible = true;
|
|
2670
2678
|
optimizeOptions = {};
|
|
2679
|
+
/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */
|
|
2680
|
+
alwaysPostpositionBackground = false;
|
|
2671
2681
|
posXSpringParams = {
|
|
2672
2682
|
mass: 1,
|
|
2673
2683
|
damping: 10,
|
|
@@ -2717,13 +2727,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2717
2727
|
shouldRelayout = true;
|
|
2718
2728
|
}
|
|
2719
2729
|
} else {
|
|
2720
|
-
const
|
|
2721
|
-
if (
|
|
2730
|
+
const groupObj = this.lyricGroupElementMap.get(entry.target);
|
|
2731
|
+
if (groupObj) {
|
|
2722
2732
|
const newSize = [entry.target.clientWidth, entry.target.clientHeight];
|
|
2723
|
-
const oldSize = this.
|
|
2733
|
+
const oldSize = this.lyricGroupSize.get(groupObj) ?? [0, 0];
|
|
2724
2734
|
if (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {
|
|
2725
|
-
this.
|
|
2726
|
-
|
|
2735
|
+
this.lyricGroupSize.set(groupObj, newSize);
|
|
2736
|
+
groupObj.onLineSizeChange(newSize);
|
|
2727
2737
|
shouldRelayout = true;
|
|
2728
2738
|
}
|
|
2729
2739
|
}
|
|
@@ -2849,7 +2859,7 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2849
2859
|
}
|
|
2850
2860
|
}
|
|
2851
2861
|
rebuildLyricLines() {
|
|
2852
|
-
for (const
|
|
2862
|
+
for (const group of this.currentLyricGroups) group.rebuildAllLines();
|
|
2853
2863
|
}
|
|
2854
2864
|
/**
|
|
2855
2865
|
* 根据当前配置处理不雅用语单词
|
|
@@ -2951,11 +2961,11 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2951
2961
|
break;
|
|
2952
2962
|
}
|
|
2953
2963
|
this.hasDuetLine = this.processedLines.some((line) => line.isDuet);
|
|
2954
|
-
for (const
|
|
2964
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
2965
|
+
this.currentLyricGroups = [];
|
|
2955
2966
|
this.interludeDots.setInterlude(void 0);
|
|
2956
|
-
this.timelineState.
|
|
2957
|
-
this.timelineState.
|
|
2958
|
-
this.setCurrentTime(0, true);
|
|
2967
|
+
this.timelineState.hotGroups.clear();
|
|
2968
|
+
this.timelineState.bufferedGroups.clear();
|
|
2959
2969
|
if (process.env.NODE_ENV !== "production") console.log("歌词处理完成", this);
|
|
2960
2970
|
}
|
|
2961
2971
|
/**
|
|
@@ -2981,19 +2991,19 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2981
2991
|
if (!timelineState.initialLayoutFinished && !timelineState.isSeeking) return;
|
|
2982
2992
|
const stateResult = computePlayerTimeState({
|
|
2983
2993
|
time,
|
|
2984
|
-
|
|
2994
|
+
currentGroups: this.currentLyricGroups,
|
|
2985
2995
|
timelineState
|
|
2986
2996
|
});
|
|
2987
2997
|
const hasBottomContent = this.bottomLine.getElement().innerHTML.trim().length > 0;
|
|
2988
2998
|
const commitResult = commitPlayerTimeState({
|
|
2989
2999
|
timelineState,
|
|
2990
3000
|
time,
|
|
2991
|
-
|
|
3001
|
+
currentGroups: this.currentLyricGroups,
|
|
2992
3002
|
hasBottomContent,
|
|
2993
3003
|
stateResult
|
|
2994
3004
|
});
|
|
2995
|
-
for (const id of commitResult.
|
|
2996
|
-
for (const id of commitResult.
|
|
3005
|
+
for (const id of commitResult.groupsToDisable) this.currentLyricGroups[id]?.disable();
|
|
3006
|
+
for (const id of commitResult.groupsToEnable) this.currentLyricGroups[id]?.enable();
|
|
2997
3007
|
if (commitResult.shouldResetScroll) this.resetScroll();
|
|
2998
3008
|
if (commitResult.shouldLayout) this.calcLayout();
|
|
2999
3009
|
}
|
|
@@ -3018,14 +3028,14 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3018
3028
|
const interlude = computeCurrentInterlude({
|
|
3019
3029
|
currentTime: this.timelineState.currentTime,
|
|
3020
3030
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3021
|
-
|
|
3031
|
+
currentGroups: this.currentLyricGroups
|
|
3022
3032
|
});
|
|
3023
3033
|
const isInterludeActive = !!interlude;
|
|
3024
3034
|
if (this.layoutState.targetAlignIndex !== this.timelineState.scrollToIndex || this.layoutState.lastInterludeState !== isInterludeActive) {
|
|
3025
3035
|
this.layoutState.lastInterludeState = isInterludeActive;
|
|
3026
3036
|
const springParams = computeLinePosYSpringParams({
|
|
3027
3037
|
enabled: this.getEnableSpring(),
|
|
3028
|
-
|
|
3038
|
+
currentGroups: this.currentLyricGroups,
|
|
3029
3039
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3030
3040
|
isSeeking: this.timelineState.isSeeking,
|
|
3031
3041
|
isInterludeActive
|
|
@@ -3043,17 +3053,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3043
3053
|
if (interlude.anchorLineIndex !== -1) curPos -= totalInterludeHeight;
|
|
3044
3054
|
}
|
|
3045
3055
|
const LINE_HEIGHT_FALLBACK = this.size[1] / 5;
|
|
3046
|
-
const scrollOffset = this.
|
|
3056
|
+
const scrollOffset = this.currentLyricGroups.slice(0, targetAlignIndex).reduce((acc, group) => acc + (this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK), 0);
|
|
3047
3057
|
this.scrollState.scrollBoundary.minOffset = -scrollOffset;
|
|
3048
3058
|
curPos -= scrollOffset;
|
|
3049
3059
|
curPos += this.size[1] * this.layoutState.alignPosition;
|
|
3050
|
-
const
|
|
3060
|
+
const curGroup = this.currentLyricGroups[targetAlignIndex];
|
|
3051
3061
|
this.layoutState.targetAlignIndex = targetAlignIndex;
|
|
3052
|
-
const isBottomFocused = targetAlignIndex === this.
|
|
3062
|
+
const isBottomFocused = targetAlignIndex === this.currentLyricGroups.length;
|
|
3053
3063
|
this.bottomLine.setFocused(isBottomFocused);
|
|
3054
|
-
|
|
3055
|
-
if (curLine) targetLineHeight = this.lyricLinesSize.get(curLine)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3056
|
-
else if (isBottomFocused) targetLineHeight = this.bottomLine.lineSize[1];
|
|
3064
|
+
const targetLineHeight = curGroup ? this.lyricGroupSize.get(curGroup)?.[1] ?? LINE_HEIGHT_FALLBACK : isBottomFocused ? this.bottomLine.lineSize[1] : 0;
|
|
3057
3065
|
if (targetLineHeight > 0) switch (this.layoutState.alignAnchor) {
|
|
3058
3066
|
case LayoutAlignAnchor.Bottom:
|
|
3059
3067
|
curPos -= targetLineHeight;
|
|
@@ -3063,13 +3071,12 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3063
3071
|
break;
|
|
3064
3072
|
case LayoutAlignAnchor.Top: break;
|
|
3065
3073
|
}
|
|
3066
|
-
const latestIndex = Math.max(...this.timelineState.
|
|
3074
|
+
const latestIndex = Math.max(...this.timelineState.bufferedGroups);
|
|
3067
3075
|
let delay = 0;
|
|
3068
3076
|
let baseDelay = sync ? 0 : .05;
|
|
3069
3077
|
let setDots = false;
|
|
3070
|
-
this.
|
|
3071
|
-
const hasBuffered = this.timelineState.
|
|
3072
|
-
const line = lineObj.getLine();
|
|
3078
|
+
this.currentLyricGroups.forEach((group, i) => {
|
|
3079
|
+
const hasBuffered = this.timelineState.bufferedGroups.has(i);
|
|
3073
3080
|
const shouldShowDots = interlude && i === interlude.anchorLineIndex + 1;
|
|
3074
3081
|
if (!setDots && shouldShowDots) {
|
|
3075
3082
|
setDots = true;
|
|
@@ -3081,31 +3088,28 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3081
3088
|
curPos += this.layoutState.interludeDotsSize[1];
|
|
3082
3089
|
curPos += dotMargin;
|
|
3083
3090
|
}
|
|
3084
|
-
const presentation =
|
|
3085
|
-
|
|
3086
|
-
lineIndex: i,
|
|
3091
|
+
const presentation = computeGroupPresentation({
|
|
3092
|
+
groupIndex: i,
|
|
3087
3093
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3088
3094
|
latestIndex,
|
|
3089
3095
|
hasBuffered,
|
|
3090
3096
|
hidePassedLines: this.hidePassedLines,
|
|
3091
3097
|
isPlaying: this.timelineState.isPlaying,
|
|
3092
3098
|
isNonDynamic: this.isNonDynamic,
|
|
3093
|
-
enableScale: this.enableScale,
|
|
3094
3099
|
enableBlur: this.enableBlur,
|
|
3095
3100
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
3096
3101
|
isCompact: window.innerWidth <= 1024,
|
|
3097
3102
|
interlude
|
|
3098
3103
|
});
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
else if (!line.isBG) curPos += this.lyricLinesSize.get(lineObj)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3104
|
+
group.setTransform(curPos, force, delay, presentation.isActive, presentation.targetOpacity, presentation.blurLevel);
|
|
3105
|
+
curPos += this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3102
3106
|
if (curPos >= 0 && !this.timelineState.isSeeking) {
|
|
3103
|
-
|
|
3107
|
+
delay += baseDelay;
|
|
3104
3108
|
if (i >= this.timelineState.scrollToIndex) baseDelay /= 1.05;
|
|
3105
3109
|
}
|
|
3106
3110
|
});
|
|
3107
3111
|
this.scrollState.scrollBoundary.maxOffset = curPos + this.scrollState.scrollOffset - this.size[1] / 2;
|
|
3108
|
-
const bottomIndex = this.
|
|
3112
|
+
const bottomIndex = this.currentLyricGroups.length;
|
|
3109
3113
|
const finalBottomBlur = computeLineBlur({
|
|
3110
3114
|
enableBlur: this.enableBlur,
|
|
3111
3115
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
@@ -3135,7 +3139,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3135
3139
|
...params
|
|
3136
3140
|
};
|
|
3137
3141
|
this.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);
|
|
3138
|
-
for (const
|
|
3142
|
+
for (const group of this.currentLyricGroups) {
|
|
3143
|
+
group.posY.updateParams(this.posYSpringParams);
|
|
3144
|
+
group.bgSlideY.updateParams(this.posYSpringParams);
|
|
3145
|
+
}
|
|
3139
3146
|
}
|
|
3140
3147
|
/**
|
|
3141
3148
|
* 设置所有歌词行在缩放大小上的弹簧属性,包括重量、弹力和阻力。
|
|
@@ -3151,8 +3158,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3151
3158
|
...this.scaleForBGSpringParams,
|
|
3152
3159
|
...params
|
|
3153
3160
|
};
|
|
3154
|
-
for (const
|
|
3155
|
-
|
|
3161
|
+
for (const group of this.currentLyricGroups) {
|
|
3162
|
+
group.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);
|
|
3163
|
+
group.bgLine?.lineTransforms.scale.updateParams(this.scaleForBGSpringParams);
|
|
3164
|
+
}
|
|
3156
3165
|
}
|
|
3157
3166
|
/**
|
|
3158
3167
|
* 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来
|
|
@@ -3224,6 +3233,23 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3224
3233
|
getCurrentTime() {
|
|
3225
3234
|
return this.timelineState.currentTime;
|
|
3226
3235
|
}
|
|
3236
|
+
/**
|
|
3237
|
+
* 设置是否让背景人声行始终后置显示
|
|
3238
|
+
*
|
|
3239
|
+
* 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;
|
|
3240
|
+
* 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示
|
|
3241
|
+
* @param enable 是否启用始终后置
|
|
3242
|
+
*/
|
|
3243
|
+
setAlwaysPostpositionBackground(enable) {
|
|
3244
|
+
if (this.alwaysPostpositionBackground === enable) return;
|
|
3245
|
+
this.alwaysPostpositionBackground = enable;
|
|
3246
|
+
this.rebuildLyricLines();
|
|
3247
|
+
this.calcLayout();
|
|
3248
|
+
}
|
|
3249
|
+
/** 获取当前是否设置了让背景人声行始终后置显示 */
|
|
3250
|
+
getAlwaysPostpositionBackground() {
|
|
3251
|
+
return this.alwaysPostpositionBackground;
|
|
3252
|
+
}
|
|
3227
3253
|
getElement() {
|
|
3228
3254
|
return this.element;
|
|
3229
3255
|
}
|
|
@@ -3234,6 +3260,194 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3234
3260
|
}
|
|
3235
3261
|
};
|
|
3236
3262
|
//#endregion
|
|
3263
|
+
//#region src/lyric-player/base/group.ts
|
|
3264
|
+
var LyricLineGroupBase = class {
|
|
3265
|
+
mainLine;
|
|
3266
|
+
bgLine;
|
|
3267
|
+
posY = new Spring(0);
|
|
3268
|
+
bgSlideY = new Spring(-80);
|
|
3269
|
+
top = 0;
|
|
3270
|
+
delay = 0;
|
|
3271
|
+
isActive = false;
|
|
3272
|
+
opacity = 1;
|
|
3273
|
+
blur = 0;
|
|
3274
|
+
isBgFirst = false;
|
|
3275
|
+
constructor(mainLine, bgLine) {
|
|
3276
|
+
this.mainLine = mainLine;
|
|
3277
|
+
this.bgLine = bgLine;
|
|
3278
|
+
}
|
|
3279
|
+
get startTime() {
|
|
3280
|
+
return this.mainLine.getLine().startTime;
|
|
3281
|
+
}
|
|
3282
|
+
get endTime() {
|
|
3283
|
+
return this.mainLine.getLine().endTime;
|
|
3284
|
+
}
|
|
3285
|
+
onLineSizeChange(size) {
|
|
3286
|
+
this.mainLine.onLineSizeChange(size);
|
|
3287
|
+
this.bgLine?.onLineSizeChange(size);
|
|
3288
|
+
}
|
|
3289
|
+
setTransform(top, force, delay, isActive, opacity, blur) {
|
|
3290
|
+
this.top = top;
|
|
3291
|
+
this.delay = delay;
|
|
3292
|
+
this.isActive = isActive;
|
|
3293
|
+
this.opacity = opacity;
|
|
3294
|
+
this.blur = blur;
|
|
3295
|
+
this.setLineTransformations(force, delay);
|
|
3296
|
+
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
3297
|
+
const hiddenSlideY = (this.lyricPlayer.getAlwaysPostpositionBackground() ? false : this.isBgFirst) ? 80 : -80;
|
|
3298
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3299
|
+
const targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;
|
|
3300
|
+
if (force || !enableSpring) {
|
|
3301
|
+
this.posY.setPosition(top);
|
|
3302
|
+
this.bgSlideY.setPosition(targetBgSlideY);
|
|
3303
|
+
this.renderStyles();
|
|
3304
|
+
} else {
|
|
3305
|
+
this.posY.setTargetPosition(top, delay);
|
|
3306
|
+
this.bgSlideY.setTargetPosition(targetBgSlideY, delay);
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
setLineTransformations(force, delay) {
|
|
3310
|
+
const enableScale = this.lyricPlayer.getEnableScale();
|
|
3311
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3312
|
+
const renderMode = this.isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID;
|
|
3313
|
+
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
3314
|
+
let mainScale = 100;
|
|
3315
|
+
if (!this.isActive && isPlaying) mainScale = SCALE_ASPECT;
|
|
3316
|
+
this.mainLine.setTransform(mainScale, 1, 0, force, delay, renderMode);
|
|
3317
|
+
let bgScale = 100;
|
|
3318
|
+
if (!this.isActive && isPlaying) bgScale = 75;
|
|
3319
|
+
this.bgLine?.setTransform(bgScale, 1, 0, force, delay, renderMode);
|
|
3320
|
+
}
|
|
3321
|
+
update(delta) {
|
|
3322
|
+
if (this.lyricPlayer.getEnableSpring()) {
|
|
3323
|
+
this.posY.update(delta);
|
|
3324
|
+
this.bgSlideY.update(delta);
|
|
3325
|
+
this.renderStyles();
|
|
3326
|
+
}
|
|
3327
|
+
this.mainLine.update(delta);
|
|
3328
|
+
this.bgLine?.update(delta);
|
|
3329
|
+
}
|
|
3330
|
+
rebuildAllLines() {
|
|
3331
|
+
this.mainLine.rebuildElement();
|
|
3332
|
+
this.bgLine?.rebuildElement();
|
|
3333
|
+
}
|
|
3334
|
+
enable(time, shouldPlay) {
|
|
3335
|
+
this.mainLine.enable(time, shouldPlay);
|
|
3336
|
+
this.bgLine?.enable(time, shouldPlay);
|
|
3337
|
+
}
|
|
3338
|
+
disable() {
|
|
3339
|
+
this.mainLine.disable();
|
|
3340
|
+
this.bgLine?.disable();
|
|
3341
|
+
}
|
|
3342
|
+
dispose() {
|
|
3343
|
+
this.mainLine.dispose();
|
|
3344
|
+
this.bgLine?.dispose();
|
|
3345
|
+
}
|
|
3346
|
+
};
|
|
3347
|
+
//#endregion
|
|
3348
|
+
//#region src/lyric-player/dom/lyric-group.ts
|
|
3349
|
+
var LyricLineGroup = class extends LyricLineGroupBase {
|
|
3350
|
+
lyricPlayer;
|
|
3351
|
+
element;
|
|
3352
|
+
bgWrapper;
|
|
3353
|
+
lastIsActive;
|
|
3354
|
+
constructor(lyricPlayer, mainLine) {
|
|
3355
|
+
super(mainLine);
|
|
3356
|
+
this.lyricPlayer = lyricPlayer;
|
|
3357
|
+
this.element = document.createElement("div");
|
|
3358
|
+
this.element.className = lyric_player_module_default.lyricLineWrapper;
|
|
3359
|
+
this.element.appendChild(mainLine.getElement());
|
|
3360
|
+
this.posY.setPosition(window.innerHeight * 2);
|
|
3361
|
+
lyricPlayer.resizeObserver.observe(this.element);
|
|
3362
|
+
}
|
|
3363
|
+
get isInSight() {
|
|
3364
|
+
const t = this.posY.getCurrentPosition();
|
|
3365
|
+
let h = this.lyricPlayer.lyricGroupSize?.get(this)?.[1];
|
|
3366
|
+
if (h === void 0 || h === 0) h = this.element.clientHeight || 0;
|
|
3367
|
+
const pb = this.lyricPlayer.size[1];
|
|
3368
|
+
const ov = this.lyricPlayer.getOverscanPx();
|
|
3369
|
+
return !(t > pb + h + ov || t < -h - ov);
|
|
3370
|
+
}
|
|
3371
|
+
show() {
|
|
3372
|
+
if (!this.element.parentElement) {
|
|
3373
|
+
const playerEl = this.lyricPlayer.getElement();
|
|
3374
|
+
const groups = this.lyricPlayer.currentLyricGroups;
|
|
3375
|
+
const myIndex = groups.indexOf(this);
|
|
3376
|
+
let referenceNode = null;
|
|
3377
|
+
if (myIndex !== -1) {
|
|
3378
|
+
for (let i = myIndex + 1; i < groups.length; i++) if (groups[i].element.parentElement === playerEl) {
|
|
3379
|
+
referenceNode = groups[i].element;
|
|
3380
|
+
break;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
playerEl.insertBefore(this.element, referenceNode);
|
|
3384
|
+
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3385
|
+
}
|
|
3386
|
+
this.mainLine.show();
|
|
3387
|
+
this.bgLine?.show();
|
|
3388
|
+
}
|
|
3389
|
+
hide() {
|
|
3390
|
+
if (this.element.parentElement) {
|
|
3391
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3392
|
+
this.element.remove();
|
|
3393
|
+
this.mainLine.teardownContent();
|
|
3394
|
+
this.bgLine?.teardownContent();
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
update(delta) {
|
|
3398
|
+
if (this.isInSight) this.show();
|
|
3399
|
+
else this.hide();
|
|
3400
|
+
super.update(delta);
|
|
3401
|
+
}
|
|
3402
|
+
addBgLine(bgLine) {
|
|
3403
|
+
if (this.bgLine) this.bgLine.dispose();
|
|
3404
|
+
if (this.bgWrapper) this.bgWrapper.remove();
|
|
3405
|
+
this.bgLine = bgLine;
|
|
3406
|
+
const bgStartTime = bgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;
|
|
3407
|
+
const mainStartTime = this.mainLine.getLine().words[0]?.startTime ?? this.mainLine.getLine().startTime;
|
|
3408
|
+
this.isBgFirst = bgStartTime < mainStartTime;
|
|
3409
|
+
if (this.mainLine.getLine().isDuet) bgLine.getElement().classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3410
|
+
this.bgWrapper = document.createElement("div");
|
|
3411
|
+
this.bgWrapper.className = lyric_player_module_default.bgWrapper;
|
|
3412
|
+
this.bgWrapper.appendChild(bgLine.getElement());
|
|
3413
|
+
if (!this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst) {
|
|
3414
|
+
this.bgWrapper.classList.add(lyric_player_module_default.bgWrapperTop);
|
|
3415
|
+
this.element.insertBefore(this.bgWrapper, this.mainLine.getElement());
|
|
3416
|
+
this.bgSlideY.setPosition(80);
|
|
3417
|
+
} else this.element.appendChild(this.bgWrapper);
|
|
3418
|
+
}
|
|
3419
|
+
renderStyles() {
|
|
3420
|
+
const y = this.posY.getCurrentPosition().toFixed(1);
|
|
3421
|
+
this.element.style.transform = `translateY(${y}px)`;
|
|
3422
|
+
this.element.style.opacity = this.opacity.toString();
|
|
3423
|
+
this.element.style.filter = `blur(${Math.min(5, this.blur)}px)`;
|
|
3424
|
+
if (!this.lyricPlayer.getEnableSpring()) this.element.style.transitionDelay = `${this.delay}ms`;
|
|
3425
|
+
if (this.bgWrapper) {
|
|
3426
|
+
if (this.lastIsActive !== this.isActive) {
|
|
3427
|
+
this.lastIsActive = this.isActive;
|
|
3428
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperActive, this.isActive);
|
|
3429
|
+
}
|
|
3430
|
+
const slideY = this.bgSlideY.getCurrentPosition();
|
|
3431
|
+
const slideYStr = slideY.toFixed(1);
|
|
3432
|
+
const activeProgress = clamp01(1 - Math.abs(slideY) / 80);
|
|
3433
|
+
const scaleStr = (.8 + activeProgress * .2).toFixed(3);
|
|
3434
|
+
this.bgWrapper.style.transform = `translateY(${slideYStr}%) scale(${scaleStr})`;
|
|
3435
|
+
const shouldBgFirst = !this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst;
|
|
3436
|
+
if (shouldBgFirst) {
|
|
3437
|
+
const currentMarginTop = -(this.bgWrapper.clientHeight || 0) * (1 - activeProgress);
|
|
3438
|
+
this.bgWrapper.style.marginTop = `${currentMarginTop.toFixed(1)}px`;
|
|
3439
|
+
} else this.bgWrapper.style.marginTop = "";
|
|
3440
|
+
const isHidden = slideYStr === (shouldBgFirst ? "80.0" : "-80.0") && !this.isActive;
|
|
3441
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperHidden, isHidden);
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
dispose() {
|
|
3445
|
+
super.dispose();
|
|
3446
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3447
|
+
this.element.remove();
|
|
3448
|
+
}
|
|
3449
|
+
};
|
|
3450
|
+
//#endregion
|
|
3237
3451
|
//#region src/utils/is-cjk.ts
|
|
3238
3452
|
const isCJK = (char) => {
|
|
3239
3453
|
return /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u.test(char);
|
|
@@ -3250,10 +3464,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3250
3464
|
blur = 0;
|
|
3251
3465
|
opacity = 1;
|
|
3252
3466
|
delay = 0;
|
|
3253
|
-
lineTransforms = {
|
|
3254
|
-
posY: new Spring(0),
|
|
3255
|
-
scale: new Spring(100)
|
|
3256
|
-
};
|
|
3467
|
+
lineTransforms = { scale: new Spring(100) };
|
|
3257
3468
|
/**
|
|
3258
3469
|
* 用于 CJK 词语边界检测的分词器
|
|
3259
3470
|
*/
|
|
@@ -3263,9 +3474,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3263
3474
|
* 用于正确处理 emoji、复合字符等
|
|
3264
3475
|
*/
|
|
3265
3476
|
static graphemeSegmenter = typeof Intl !== "undefined" && Intl.Segmenter ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
3266
|
-
|
|
3267
|
-
setTransform(top = this.top, scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3268
|
-
this.top = top;
|
|
3477
|
+
setTransform(scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3269
3478
|
this.scale = scale;
|
|
3270
3479
|
this.opacity = opacity;
|
|
3271
3480
|
this.blur = blur;
|
|
@@ -3388,6 +3597,7 @@ function getMeasurementContext() {
|
|
|
3388
3597
|
* 用于平衡歌词行在换行后的各行长度
|
|
3389
3598
|
*/
|
|
3390
3599
|
var LineBalancer = class {
|
|
3600
|
+
mainElement;
|
|
3391
3601
|
isBalancing = false;
|
|
3392
3602
|
lastBalancedContainerWidth = -1;
|
|
3393
3603
|
constructor(mainElement) {
|
|
@@ -3711,13 +3921,9 @@ function generateFadeGradient(width, padding = 0, bright = "rgba(0,0,0,var(--bri
|
|
|
3711
3921
|
const leftPos = (1 - widthInTotal) / 2;
|
|
3712
3922
|
return [`linear-gradient(to right,${bright} ${leftPos * 100}%,${dark} ${(leftPos + widthInTotal) * 100}%)`, totalAspect];
|
|
3713
3923
|
}
|
|
3714
|
-
var RawLyricLineMouseEvent = class extends MouseEvent {
|
|
3715
|
-
constructor(line, event) {
|
|
3716
|
-
super(event.type, event);
|
|
3717
|
-
this.line = line;
|
|
3718
|
-
}
|
|
3719
|
-
};
|
|
3720
3924
|
var LyricLineEl = class extends LyricLineBase {
|
|
3925
|
+
lyricPlayer;
|
|
3926
|
+
lyricLine;
|
|
3721
3927
|
element = document.createElement("div");
|
|
3722
3928
|
splittedWords = [];
|
|
3723
3929
|
built = false;
|
|
@@ -3743,12 +3949,9 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3743
3949
|
super();
|
|
3744
3950
|
this.lyricPlayer = lyricPlayer;
|
|
3745
3951
|
this.lyricLine = lyricLine;
|
|
3746
|
-
this._prevParentEl = lyricPlayer.getElement();
|
|
3747
|
-
lyricPlayer.resizeObserver.observe(this.element);
|
|
3748
3952
|
this.element.setAttribute("class", lyric_player_module_default.lyricLine);
|
|
3749
3953
|
if (this.lyricLine.isBG) this.element.classList.add(lyric_player_module_default.lyricBgLine);
|
|
3750
3954
|
if (this.lyricLine.isDuet) this.element.classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3751
|
-
this.lineTransforms.posY.setPosition(window.innerHeight * 2);
|
|
3752
3955
|
this.element.appendChild(document.createElement("div"));
|
|
3753
3956
|
this.element.appendChild(document.createElement("div"));
|
|
3754
3957
|
this.element.appendChild(document.createElement("div"));
|
|
@@ -3761,33 +3964,6 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3761
3964
|
if (LyricLineBase.wordSegmenter) this.balancer = new LineBalancer(main);
|
|
3762
3965
|
this.rebuildStyle();
|
|
3763
3966
|
}
|
|
3764
|
-
listenersMap = /* @__PURE__ */ new Map();
|
|
3765
|
-
onMouseEvent = (e) => {
|
|
3766
|
-
const wrapped = new RawLyricLineMouseEvent(this, e);
|
|
3767
|
-
for (const listener of this.listenersMap.get(e.type) ?? []) listener.call(this, wrapped);
|
|
3768
|
-
if (!this.dispatchEvent(wrapped) || wrapped.defaultPrevented) {
|
|
3769
|
-
e.preventDefault();
|
|
3770
|
-
e.stopPropagation();
|
|
3771
|
-
e.stopImmediatePropagation();
|
|
3772
|
-
}
|
|
3773
|
-
};
|
|
3774
|
-
addMouseEventListener(type, callback, options) {
|
|
3775
|
-
if (callback) {
|
|
3776
|
-
const listeners = this.listenersMap.get(type) ?? /* @__PURE__ */ new Set();
|
|
3777
|
-
if (listeners.size === 0) this.element.addEventListener(type, this.onMouseEvent, options);
|
|
3778
|
-
listeners.add(callback);
|
|
3779
|
-
this.listenersMap.set(type, listeners);
|
|
3780
|
-
}
|
|
3781
|
-
}
|
|
3782
|
-
removeMouseEventListener(type, callback, options) {
|
|
3783
|
-
if (callback) {
|
|
3784
|
-
const listeners = this.listenersMap.get(type);
|
|
3785
|
-
if (listeners) {
|
|
3786
|
-
listeners.delete(callback);
|
|
3787
|
-
if (listeners.size === 0) this.element.removeEventListener(type, this.onMouseEvent, options);
|
|
3788
|
-
}
|
|
3789
|
-
}
|
|
3790
|
-
}
|
|
3791
3967
|
areWordsOnSameLine(word1, word2) {
|
|
3792
3968
|
if (word1?.mainElement && word2?.mainElement) {
|
|
3793
3969
|
const word1el = word1.mainElement;
|
|
@@ -3880,34 +4056,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3880
4056
|
getLine() {
|
|
3881
4057
|
return this.lyricLine;
|
|
3882
4058
|
}
|
|
3883
|
-
_prevParentEl;
|
|
3884
4059
|
lastStyle = "";
|
|
3885
4060
|
show() {
|
|
3886
|
-
if (!this.element.parentElement) {
|
|
3887
|
-
this._prevParentEl.appendChild(this.element);
|
|
3888
|
-
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3889
|
-
}
|
|
3890
4061
|
if (!this.built) {
|
|
3891
4062
|
this.rebuildElement();
|
|
3892
4063
|
this.built = true;
|
|
3893
4064
|
this.updateMaskImageSync();
|
|
3894
4065
|
}
|
|
3895
|
-
this.rebuildStyle();
|
|
3896
|
-
}
|
|
3897
|
-
hide() {
|
|
3898
|
-
if (this.element.parentElement) {
|
|
3899
|
-
this._prevParentEl.removeChild(this.element);
|
|
3900
|
-
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3901
|
-
}
|
|
3902
|
-
if (this.built) {
|
|
3903
|
-
this.disposeElements();
|
|
3904
|
-
this.built = false;
|
|
3905
|
-
}
|
|
3906
4066
|
}
|
|
3907
4067
|
rebuildStyle() {
|
|
3908
4068
|
let style = "";
|
|
3909
|
-
style += `transform:
|
|
3910
|
-
if (!this.lyricPlayer.getEnableSpring()
|
|
4069
|
+
style += `transform: scale(${(this.lineTransforms.scale.getCurrentPosition() / 100).toFixed(4)});`;
|
|
4070
|
+
if (!this.lyricPlayer.getEnableSpring()) style += `transition-delay:${this.delay}ms;`;
|
|
3911
4071
|
style += `filter:blur(${Math.min(5, this.blur)}px);`;
|
|
3912
4072
|
if (style !== this.lastStyle) {
|
|
3913
4073
|
this.lastStyle = style;
|
|
@@ -3920,7 +4080,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3920
4080
|
const trans = this.element.children[1];
|
|
3921
4081
|
const roman = this.element.children[2];
|
|
3922
4082
|
if (this.lyricPlayer._getIsNonDynamic()) {
|
|
3923
|
-
main.
|
|
4083
|
+
main.textContent = this.lyricLine.words.map((w) => this.lyricPlayer.processObsceneWord(w)).join("");
|
|
3924
4084
|
this.setSubLinesText(trans, roman);
|
|
3925
4085
|
return;
|
|
3926
4086
|
}
|
|
@@ -3933,8 +4093,8 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3933
4093
|
}
|
|
3934
4094
|
/** 设置翻译与音译行文本 */
|
|
3935
4095
|
setSubLinesText(trans, roman) {
|
|
3936
|
-
trans.
|
|
3937
|
-
roman.
|
|
4096
|
+
trans.textContent = this.lyricLine.translatedLyric;
|
|
4097
|
+
roman.textContent = this.lyricLine.romanLyric;
|
|
3938
4098
|
}
|
|
3939
4099
|
getRubyCharCount(word) {
|
|
3940
4100
|
return (word.ruby ?? []).reduce((total, ruby) => total + ruby.word.length, 0);
|
|
@@ -3952,7 +4112,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3952
4112
|
const rubySegments = this.getRubySegments(word);
|
|
3953
4113
|
for (const ruby of rubySegments) {
|
|
3954
4114
|
const rubyPartEl = document.createElement("span");
|
|
3955
|
-
rubyPartEl.
|
|
4115
|
+
rubyPartEl.textContent = ruby.word;
|
|
3956
4116
|
rubyPartEl.dataset.startTime = String(ruby.startTime);
|
|
3957
4117
|
rubyPartEl.dataset.endTime = String(ruby.endTime);
|
|
3958
4118
|
rubyWordEl.appendChild(rubyPartEl);
|
|
@@ -3969,24 +4129,24 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3969
4129
|
const trimmedWord = displayWord.trim();
|
|
3970
4130
|
if (LyricLineBase.graphemeSegmenter) for (const { segment } of LyricLineBase.graphemeSegmenter.segment(trimmedWord)) {
|
|
3971
4131
|
const charEl = document.createElement("span");
|
|
3972
|
-
charEl.
|
|
4132
|
+
charEl.textContent = segment;
|
|
3973
4133
|
subElements.push(charEl);
|
|
3974
4134
|
wordContainer.appendChild(charEl);
|
|
3975
4135
|
}
|
|
3976
4136
|
else for (const segment of Array.from(trimmedWord)) {
|
|
3977
4137
|
const charEl = document.createElement("span");
|
|
3978
|
-
charEl.
|
|
4138
|
+
charEl.textContent = segment;
|
|
3979
4139
|
subElements.push(charEl);
|
|
3980
4140
|
wordContainer.appendChild(charEl);
|
|
3981
4141
|
}
|
|
3982
4142
|
} else if (hasRomanLine) {
|
|
3983
4143
|
const wordEl = document.createElement("div");
|
|
3984
|
-
wordEl.
|
|
4144
|
+
wordEl.textContent = displayWord.trim();
|
|
3985
4145
|
wordContainer.appendChild(wordEl);
|
|
3986
|
-
} else if (romanWord.length === 0) wordContainer.
|
|
4146
|
+
} else if (romanWord.length === 0) wordContainer.textContent = displayWord.trim();
|
|
3987
4147
|
if (hasRomanLine) {
|
|
3988
4148
|
const romanWordEl = document.createElement("div");
|
|
3989
|
-
romanWordEl.
|
|
4149
|
+
romanWordEl.textContent = romanWord.length > 0 ? romanWord : "\xA0";
|
|
3990
4150
|
romanWordEl.classList.add(lyric_player_module_default.romanWord);
|
|
3991
4151
|
wordContainer.appendChild(romanWordEl);
|
|
3992
4152
|
}
|
|
@@ -4100,7 +4260,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4100
4260
|
const glow = el.animate(frames, {
|
|
4101
4261
|
duration: animateDu,
|
|
4102
4262
|
delay: Number.isFinite(wordDe) ? wordDe : 0,
|
|
4103
|
-
id: `emphasize-word-${el.
|
|
4263
|
+
id: `emphasize-word-${el.textContent}-${i}`,
|
|
4104
4264
|
iterations: 1,
|
|
4105
4265
|
composite: "replace",
|
|
4106
4266
|
fill: "both"
|
|
@@ -4350,25 +4510,19 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4350
4510
|
this.element.style.setProperty("--bright-mask-alpha", this.currentBrightAlpha.toFixed(3));
|
|
4351
4511
|
this.element.style.setProperty("--dark-mask-alpha", this.currentDarkAlpha.toFixed(3));
|
|
4352
4512
|
}
|
|
4353
|
-
setTransform(
|
|
4354
|
-
super.setTransform(
|
|
4513
|
+
setTransform(scale = this.scale, opacity = 1, blur = 0, force = false, delay = 0, mode = LyricLineRenderMode.SOLID) {
|
|
4514
|
+
super.setTransform(scale, opacity, blur, force, delay);
|
|
4355
4515
|
this.renderMode = mode;
|
|
4356
|
-
const beforeInSight = this.isInSight;
|
|
4357
4516
|
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
4358
|
-
this.top =
|
|
4517
|
+
this.top = 0;
|
|
4359
4518
|
this.scale = scale;
|
|
4360
4519
|
this.delay = delay * 1e3 | 0;
|
|
4361
4520
|
const main = this.element.children[0];
|
|
4362
4521
|
main.style.opacity = `${opacity}`;
|
|
4363
4522
|
if (force || !enableSpring) {
|
|
4364
4523
|
this.blur = Math.min(32, blur);
|
|
4365
|
-
this.lineTransforms.posY.setPosition(top);
|
|
4366
4524
|
this.lineTransforms.scale.setPosition(scale);
|
|
4367
|
-
|
|
4368
|
-
const afterInSight = this.isInSight;
|
|
4369
|
-
if (beforeInSight || afterInSight) this.show();
|
|
4370
|
-
else this.hide();
|
|
4371
|
-
} else this.rebuildStyle();
|
|
4525
|
+
this.rebuildStyle();
|
|
4372
4526
|
const currentScale = this.lineTransforms.scale.getCurrentPosition();
|
|
4373
4527
|
this.updateMaskAlphaTargets(currentScale / 100);
|
|
4374
4528
|
this.currentBrightAlpha = this.targetBrightAlpha;
|
|
@@ -4376,35 +4530,31 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4376
4530
|
this.element.style.setProperty("--bright-mask-alpha", String(this.currentBrightAlpha));
|
|
4377
4531
|
this.element.style.setProperty("--dark-mask-alpha", String(this.currentDarkAlpha));
|
|
4378
4532
|
} else {
|
|
4379
|
-
this.lineTransforms.posY.setTargetPosition(top, delay);
|
|
4380
4533
|
this.lineTransforms.scale.setTargetPosition(scale);
|
|
4381
4534
|
if (this.blur !== Math.min(5, blur)) {
|
|
4382
4535
|
this.blur = Math.min(5, blur);
|
|
4383
|
-
|
|
4384
|
-
this.element.style.filter = `blur(${roundedBlur}px)`;
|
|
4536
|
+
this.element.style.filter = `blur(${blur.toFixed(3)}px)`;
|
|
4385
4537
|
}
|
|
4386
4538
|
}
|
|
4387
4539
|
}
|
|
4388
4540
|
update(delta = 0) {
|
|
4389
4541
|
if (!this.lyricPlayer.getEnableSpring()) return;
|
|
4390
|
-
this.lineTransforms.posY.update(delta);
|
|
4391
4542
|
this.lineTransforms.scale.update(delta);
|
|
4392
|
-
|
|
4393
|
-
|
|
4543
|
+
this.rebuildStyle();
|
|
4544
|
+
if (!this.built) return;
|
|
4394
4545
|
const currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;
|
|
4395
4546
|
this.updateMaskAlphaTargets(currentScale);
|
|
4396
4547
|
this.applyAlphaToDom(delta);
|
|
4397
4548
|
}
|
|
4549
|
+
/** @internal */
|
|
4398
4550
|
_getDebugTargetPos() {
|
|
4399
4551
|
return `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;
|
|
4400
4552
|
}
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
const ov = this.lyricPlayer.getOverscanPx();
|
|
4407
|
-
return !(t > pb + h + ov || b < -h - ov);
|
|
4553
|
+
teardownContent() {
|
|
4554
|
+
if (this.built) {
|
|
4555
|
+
this.disposeElements();
|
|
4556
|
+
this.built = false;
|
|
4557
|
+
}
|
|
4408
4558
|
}
|
|
4409
4559
|
disposeElements() {
|
|
4410
4560
|
this.balancer?.reset();
|
|
@@ -4437,13 +4587,29 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4437
4587
|
//#endregion
|
|
4438
4588
|
//#region src/lyric-player/dom/index.ts
|
|
4439
4589
|
/**
|
|
4440
|
-
*
|
|
4590
|
+
* 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素
|
|
4441
4591
|
*/
|
|
4442
4592
|
var LyricLineMouseEvent = class extends MouseEvent {
|
|
4443
|
-
|
|
4593
|
+
lineIndex;
|
|
4594
|
+
line;
|
|
4595
|
+
bgLine;
|
|
4596
|
+
/**
|
|
4597
|
+
* 自定义标志位,用于记录外部是否调用了 `stopPropagation`
|
|
4598
|
+
*/
|
|
4599
|
+
isPropagationStopped = false;
|
|
4600
|
+
constructor(lineIndex, line, bgLine, event) {
|
|
4444
4601
|
super(`line-${event.type}`, event);
|
|
4445
4602
|
this.lineIndex = lineIndex;
|
|
4446
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();
|
|
4447
4613
|
}
|
|
4448
4614
|
};
|
|
4449
4615
|
/**
|
|
@@ -4452,7 +4618,8 @@ var LyricLineMouseEvent = class extends MouseEvent {
|
|
|
4452
4618
|
* 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
|
|
4453
4619
|
*/
|
|
4454
4620
|
var DomLyricPlayer = class extends LyricPlayerBase {
|
|
4455
|
-
|
|
4621
|
+
abortController = new AbortController();
|
|
4622
|
+
currentLyricGroups = [];
|
|
4456
4623
|
onResize() {
|
|
4457
4624
|
const computedStyles = getComputedStyle(this.element);
|
|
4458
4625
|
this._baseFontSize = Number.parseFloat(computedStyles.fontSize);
|
|
@@ -4461,10 +4628,18 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4461
4628
|
supportPlusLighter = CSS.supports("mix-blend-mode", "plus-lighter");
|
|
4462
4629
|
supportMaskImage = CSS.supports("mask-image", "none");
|
|
4463
4630
|
innerSize = [0, 0];
|
|
4464
|
-
|
|
4465
|
-
const
|
|
4466
|
-
if (!
|
|
4467
|
-
|
|
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) {
|
|
4468
4643
|
e.stopPropagation();
|
|
4469
4644
|
e.stopImmediatePropagation();
|
|
4470
4645
|
}
|
|
@@ -4485,11 +4660,16 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4485
4660
|
this.onResize();
|
|
4486
4661
|
this.element.classList.add("amll-lyric-player", "dom");
|
|
4487
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 });
|
|
4488
4665
|
}
|
|
4489
4666
|
rebuildStyle() {}
|
|
4490
4667
|
setWordFadeWidth(value = .5) {
|
|
4491
4668
|
super.setWordFadeWidth(value);
|
|
4492
|
-
for (const
|
|
4669
|
+
for (const group of this.currentLyricGroups) {
|
|
4670
|
+
group.mainLine.updateMaskImageSync();
|
|
4671
|
+
group.bgLine?.updateMaskImageSync();
|
|
4672
|
+
}
|
|
4493
4673
|
}
|
|
4494
4674
|
/**
|
|
4495
4675
|
* 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误
|
|
@@ -4501,36 +4681,43 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4501
4681
|
if (this.hasDuetLine) this.element.classList.add(lyric_player_module_default.hasDuetLine);
|
|
4502
4682
|
else this.element.classList.remove(lyric_player_module_default.hasDuetLine);
|
|
4503
4683
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${initialTime}`);
|
|
4504
|
-
for (const
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
this.currentLyricLineObjects = this.processedLines.map((line, i) => {
|
|
4684
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4685
|
+
this.currentLyricGroups = [];
|
|
4686
|
+
let currentGroup = null;
|
|
4687
|
+
for (let i = 0; i < this.processedLines.length; i++) {
|
|
4688
|
+
const line = this.processedLines[i];
|
|
4510
4689
|
const lineEl = new LyricLineEl(this, line);
|
|
4511
|
-
lineEl.addMouseEventListener("click", this.onLineClickedHandler);
|
|
4512
|
-
lineEl.addMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4513
4690
|
this.lyricLinesIndexes.set(lineEl, i);
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4691
|
+
if (!line.isBG || !currentGroup) {
|
|
4692
|
+
currentGroup = new LyricLineGroup(this, lineEl);
|
|
4693
|
+
this.currentLyricGroups.push(currentGroup);
|
|
4694
|
+
this.lyricGroupElementMap.set(currentGroup.element, currentGroup);
|
|
4695
|
+
} else currentGroup.addBgLine(lineEl);
|
|
4696
|
+
}
|
|
4517
4697
|
this.setLinePosXSpringParams({});
|
|
4518
4698
|
this.setLinePosYSpringParams({});
|
|
4519
4699
|
this.setLineScaleSpringParams({});
|
|
4700
|
+
this.setCurrentTime(initialTime, true);
|
|
4520
4701
|
this.calcLayout(true);
|
|
4521
4702
|
this.update(0);
|
|
4522
4703
|
}
|
|
4523
4704
|
pause() {
|
|
4524
4705
|
super.pause();
|
|
4525
|
-
this.element.classList.remove(
|
|
4706
|
+
this.element.classList.remove(lyric_player_module_default.playing);
|
|
4526
4707
|
this.interludeDots.pause();
|
|
4527
|
-
for (const
|
|
4708
|
+
for (const group of this.currentLyricGroups) {
|
|
4709
|
+
group.mainLine.pause();
|
|
4710
|
+
group.bgLine?.pause();
|
|
4711
|
+
}
|
|
4528
4712
|
}
|
|
4529
4713
|
resume() {
|
|
4530
4714
|
super.resume();
|
|
4531
|
-
this.element.classList.add(
|
|
4715
|
+
this.element.classList.add(lyric_player_module_default.playing);
|
|
4532
4716
|
this.interludeDots.resume();
|
|
4533
|
-
for (const
|
|
4717
|
+
for (const group of this.currentLyricGroups) {
|
|
4718
|
+
group.mainLine.resume();
|
|
4719
|
+
group.bgLine?.resume();
|
|
4720
|
+
}
|
|
4534
4721
|
}
|
|
4535
4722
|
update(delta = 0) {
|
|
4536
4723
|
if (!this.timelineState.initialLayoutFinished) return;
|
|
@@ -4538,12 +4725,13 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4538
4725
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${this.timelineState.currentTime}`);
|
|
4539
4726
|
if (!this.isPageVisible) return;
|
|
4540
4727
|
const deltaS = delta / 1e3;
|
|
4541
|
-
for (const
|
|
4728
|
+
for (const group of this.currentLyricGroups) group.update(deltaS);
|
|
4542
4729
|
}
|
|
4543
4730
|
dispose() {
|
|
4544
4731
|
super.dispose();
|
|
4732
|
+
this.abortController.abort();
|
|
4545
4733
|
this.element.remove();
|
|
4546
|
-
for (const
|
|
4734
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4547
4735
|
this.bottomLine.dispose();
|
|
4548
4736
|
this.interludeDots.dispose();
|
|
4549
4737
|
}
|