@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.cjs
CHANGED
|
@@ -39,6 +39,7 @@ function clamp1(x) {
|
|
|
39
39
|
return Math.max(1, x);
|
|
40
40
|
}
|
|
41
41
|
var BaseRenderer = class extends AbstractBaseRenderer {
|
|
42
|
+
canvas;
|
|
42
43
|
observer;
|
|
43
44
|
flowSpeed = 1;
|
|
44
45
|
currerntRenderScale = .75;
|
|
@@ -563,10 +564,10 @@ function generateControlPoints(width, height, variationFraction = randomRange(.4
|
|
|
563
564
|
}
|
|
564
565
|
//#endregion
|
|
565
566
|
//#region \0raw:/home/runner/work/applemusic-like-lyrics/applemusic-like-lyrics/packages/core/src/bg-render/mesh-renderer/mesh.frag.glsl
|
|
566
|
-
var mesh_frag_default = "precision
|
|
567
|
+
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";
|
|
567
568
|
//#endregion
|
|
568
569
|
//#region \0raw:/home/runner/work/applemusic-like-lyrics/applemusic-like-lyrics/packages/core/src/bg-render/mesh-renderer/mesh.vert.glsl
|
|
569
|
-
var mesh_vert_default = "precision
|
|
570
|
+
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";
|
|
570
571
|
//#endregion
|
|
571
572
|
//#region src/bg-render/mesh-renderer/index.ts
|
|
572
573
|
/**
|
|
@@ -597,6 +598,7 @@ function easeInOutSine(x) {
|
|
|
597
598
|
return -(Math.cos(Math.PI * x) - 1) / 2;
|
|
598
599
|
}
|
|
599
600
|
var GLProgram = class {
|
|
601
|
+
label;
|
|
600
602
|
gl;
|
|
601
603
|
program;
|
|
602
604
|
vertexShader;
|
|
@@ -678,6 +680,10 @@ var GLProgram = class {
|
|
|
678
680
|
}
|
|
679
681
|
};
|
|
680
682
|
var Mesh = class {
|
|
683
|
+
gl;
|
|
684
|
+
attrPos;
|
|
685
|
+
attrColor;
|
|
686
|
+
attrUV;
|
|
681
687
|
vertexWidth = 0;
|
|
682
688
|
vertexHeight = 0;
|
|
683
689
|
vertexBuffer;
|
|
@@ -1100,6 +1106,7 @@ var BHPMesh = class extends Mesh {
|
|
|
1100
1106
|
}
|
|
1101
1107
|
};
|
|
1102
1108
|
var GLTexture = class {
|
|
1109
|
+
gl;
|
|
1103
1110
|
tex;
|
|
1104
1111
|
constructor(gl, albumImageData) {
|
|
1105
1112
|
this.gl = gl;
|
|
@@ -1265,11 +1272,14 @@ var MeshGradientRenderer = class extends BaseRenderer {
|
|
|
1265
1272
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1266
1273
|
this.mainProgram.use();
|
|
1267
1274
|
gl.activeTexture(gl.TEXTURE0);
|
|
1268
|
-
|
|
1275
|
+
const uTime = tickTime / 1e4;
|
|
1269
1276
|
this.mainProgram.setUniform1f("u_aspect", this.manualControl ? 1 : this.canvas.width / this.canvas.height);
|
|
1270
1277
|
this.mainProgram.setUniform1i("u_texture", 0);
|
|
1271
1278
|
this.mainProgram.setUniform1f("u_volume", this.volume);
|
|
1272
1279
|
this.mainProgram.setUniform1f("u_alpha", 1);
|
|
1280
|
+
const angle = (uTime + this.volume) * 2;
|
|
1281
|
+
this.mainProgram.setUniform1f("u_sinAngle", Math.sin(angle));
|
|
1282
|
+
this.mainProgram.setUniform1f("u_cosAngle", Math.cos(angle));
|
|
1273
1283
|
state.texture.bind();
|
|
1274
1284
|
state.mesh.bind();
|
|
1275
1285
|
state.mesh.draw();
|
|
@@ -1507,6 +1517,7 @@ var TimedContainer = class extends _pixi_display.Container {
|
|
|
1507
1517
|
time = 0;
|
|
1508
1518
|
};
|
|
1509
1519
|
var PixiRenderer = class extends BaseRenderer {
|
|
1520
|
+
canvas;
|
|
1510
1521
|
app;
|
|
1511
1522
|
curContainer;
|
|
1512
1523
|
staticMode = false;
|
|
@@ -1731,8 +1742,11 @@ var BackgroundRender = class BackgroundRender {
|
|
|
1731
1742
|
//#region src/styles/lyric-player.module.css
|
|
1732
1743
|
var lyric_player_module_default = {
|
|
1733
1744
|
"active": "FmKaba_active",
|
|
1745
|
+
"bgWrapper": "FmKaba_bgWrapper",
|
|
1746
|
+
"bgWrapperActive": "FmKaba_bgWrapperActive",
|
|
1747
|
+
"bgWrapperHidden": "FmKaba_bgWrapperHidden",
|
|
1748
|
+
"bgWrapperTop": "FmKaba_bgWrapperTop",
|
|
1734
1749
|
"bottomLine": "FmKaba_bottomLine",
|
|
1735
|
-
"dirty": "FmKaba_dirty",
|
|
1736
1750
|
"disableSpring": "FmKaba_disableSpring",
|
|
1737
1751
|
"duet": "FmKaba_duet",
|
|
1738
1752
|
"emphasize": "FmKaba_emphasize",
|
|
@@ -1743,8 +1757,10 @@ var lyric_player_module_default = {
|
|
|
1743
1757
|
"lyricBgLine": "FmKaba_lyricBgLine",
|
|
1744
1758
|
"lyricDuetLine": "FmKaba_lyricDuetLine",
|
|
1745
1759
|
"lyricLine": "FmKaba_lyricLine",
|
|
1760
|
+
"lyricLineWrapper": "FmKaba_lyricLineWrapper",
|
|
1746
1761
|
"lyricMainLine": "FmKaba_lyricMainLine",
|
|
1747
1762
|
"lyricSubLine": "FmKaba_lyricSubLine",
|
|
1763
|
+
"playing": "FmKaba_playing",
|
|
1748
1764
|
"romanWord": "FmKaba_romanWord",
|
|
1749
1765
|
"rubyWord": "FmKaba_rubyWord",
|
|
1750
1766
|
"tmpDisableTransition": "FmKaba_tmpDisableTransition",
|
|
@@ -1845,27 +1861,31 @@ function cleanUnintentionalOverlaps(lines) {
|
|
|
1845
1861
|
* 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试最多提前 400ms 或上一行时长的 30%
|
|
1846
1862
|
*/
|
|
1847
1863
|
function tryAdvanceStartTime(lines) {
|
|
1848
|
-
|
|
1864
|
+
const defaultAdvanceAmount = 600;
|
|
1865
|
+
const fallbackAdvanceAmount = 400;
|
|
1866
|
+
const fallbackAdvanceRatio = .3;
|
|
1867
|
+
let prevLineStartTime = 0;
|
|
1868
|
+
let prevLineEndTime = 0;
|
|
1869
|
+
let prevMainGroupStartTime = 0;
|
|
1870
|
+
let prevMainGroupEndTime = 0;
|
|
1871
|
+
let hasPrevLine = false;
|
|
1872
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1849
1873
|
const line = lines[i];
|
|
1850
1874
|
if (line.isBG) continue;
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
let prevIdx = i - 1;
|
|
1854
|
-
if (lines[prevIdx].isBG) prevIdx--;
|
|
1855
|
-
if (prevIdx >= 0) prevLine = lines[prevIdx];
|
|
1856
|
-
}
|
|
1875
|
+
const originalStartTime = line.startTime;
|
|
1876
|
+
const originalEndTime = line.endTime;
|
|
1857
1877
|
let targetAdvanceAmount = 0;
|
|
1858
1878
|
let safeBoundary = 0;
|
|
1859
|
-
if (
|
|
1860
|
-
targetAdvanceAmount =
|
|
1861
|
-
safeBoundary =
|
|
1879
|
+
if (hasPrevLine) if (originalStartTime >= prevLineEndTime) {
|
|
1880
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1881
|
+
safeBoundary = prevMainGroupEndTime;
|
|
1862
1882
|
} else {
|
|
1863
|
-
targetAdvanceAmount =
|
|
1864
|
-
const prevDuration =
|
|
1865
|
-
safeBoundary =
|
|
1883
|
+
targetAdvanceAmount = fallbackAdvanceAmount;
|
|
1884
|
+
const prevDuration = prevLineEndTime - prevLineStartTime;
|
|
1885
|
+
safeBoundary = prevLineStartTime + prevDuration * fallbackAdvanceRatio;
|
|
1866
1886
|
}
|
|
1867
1887
|
else {
|
|
1868
|
-
targetAdvanceAmount =
|
|
1888
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1869
1889
|
safeBoundary = 0;
|
|
1870
1890
|
}
|
|
1871
1891
|
const targetTime = line.startTime - targetAdvanceAmount;
|
|
@@ -1873,6 +1893,20 @@ function tryAdvanceStartTime(lines) {
|
|
|
1873
1893
|
if (newStartTime < line.startTime) line.startTime = newStartTime;
|
|
1874
1894
|
const nextLine = lines[i + 1];
|
|
1875
1895
|
if (nextLine?.isBG) nextLine.startTime = line.startTime;
|
|
1896
|
+
if (hasPrevLine) if (originalStartTime < prevMainGroupEndTime && originalEndTime > prevMainGroupStartTime) {
|
|
1897
|
+
prevMainGroupStartTime = Math.min(prevMainGroupStartTime, originalStartTime);
|
|
1898
|
+
prevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);
|
|
1899
|
+
} else {
|
|
1900
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1901
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1902
|
+
}
|
|
1903
|
+
else {
|
|
1904
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1905
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1906
|
+
}
|
|
1907
|
+
prevLineStartTime = originalStartTime;
|
|
1908
|
+
prevLineEndTime = originalEndTime;
|
|
1909
|
+
hasPrevLine = true;
|
|
1876
1910
|
}
|
|
1877
1911
|
}
|
|
1878
1912
|
/**
|
|
@@ -2150,6 +2184,7 @@ function solveSpring(from, velocity, to, delay = 0, params) {
|
|
|
2150
2184
|
//#endregion
|
|
2151
2185
|
//#region src/lyric-player/base/bottom-line.ts
|
|
2152
2186
|
var BottomLineEl = class {
|
|
2187
|
+
lyricPlayer;
|
|
2153
2188
|
element = document.createElement("div");
|
|
2154
2189
|
left = 0;
|
|
2155
2190
|
top = 0;
|
|
@@ -2272,19 +2307,19 @@ const LayoutAlignAnchor = {
|
|
|
2272
2307
|
function computeCurrentInterlude(input) {
|
|
2273
2308
|
const currentTime = input.currentTime + 20;
|
|
2274
2309
|
const currentIndex = input.scrollToIndex;
|
|
2275
|
-
const
|
|
2310
|
+
const groups = input.currentGroups;
|
|
2276
2311
|
const checkGap = (k) => {
|
|
2277
|
-
if (k < -1 || k >=
|
|
2278
|
-
const
|
|
2279
|
-
const
|
|
2280
|
-
const gapStart =
|
|
2281
|
-
const gapEnd = Math.max(gapStart,
|
|
2282
|
-
if (gapEnd - gapStart < 4e3) return;
|
|
2312
|
+
if (k < -1 || k >= groups.length - 1) return void 0;
|
|
2313
|
+
const prevGroup = k === -1 ? null : groups[k];
|
|
2314
|
+
const nextGroup = groups[k + 1];
|
|
2315
|
+
const gapStart = prevGroup ? prevGroup.endTime : 0;
|
|
2316
|
+
const gapEnd = Math.max(gapStart, nextGroup.startTime - 250);
|
|
2317
|
+
if (gapEnd - gapStart < 4e3) return void 0;
|
|
2283
2318
|
if (gapEnd > currentTime && gapStart < currentTime) return {
|
|
2284
2319
|
startTime: Math.max(gapStart, currentTime),
|
|
2285
2320
|
endTime: gapEnd,
|
|
2286
2321
|
anchorLineIndex: k,
|
|
2287
|
-
isNextDuet:
|
|
2322
|
+
isNextDuet: nextGroup.mainLine.getLine().isDuet
|
|
2288
2323
|
};
|
|
2289
2324
|
};
|
|
2290
2325
|
return checkGap(currentIndex - 1) || checkGap(currentIndex) || checkGap(currentIndex + 1);
|
|
@@ -2297,8 +2332,8 @@ function computeCurrentInterlude(input) {
|
|
|
2297
2332
|
* - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping
|
|
2298
2333
|
*/
|
|
2299
2334
|
function computeLinePosYSpringParams(input) {
|
|
2300
|
-
const { enabled,
|
|
2301
|
-
if (!enabled ||
|
|
2335
|
+
const { enabled, currentGroups, scrollToIndex, isSeeking, isInterludeActive } = input;
|
|
2336
|
+
if (!enabled || currentGroups.length === 0) return { shouldUpdate: false };
|
|
2302
2337
|
if (isSeeking || isInterludeActive) return {
|
|
2303
2338
|
shouldUpdate: true,
|
|
2304
2339
|
params: {
|
|
@@ -2306,10 +2341,10 @@ function computeLinePosYSpringParams(input) {
|
|
|
2306
2341
|
damping: 15
|
|
2307
2342
|
}
|
|
2308
2343
|
};
|
|
2309
|
-
const
|
|
2310
|
-
const
|
|
2311
|
-
if (!
|
|
2312
|
-
const interval =
|
|
2344
|
+
const currentGroup = currentGroups[scrollToIndex];
|
|
2345
|
+
const prevGroup = currentGroups[scrollToIndex - 1];
|
|
2346
|
+
if (!currentGroup || !prevGroup) return { shouldUpdate: false };
|
|
2347
|
+
const interval = currentGroup.startTime - prevGroup.startTime;
|
|
2313
2348
|
const MIN_INTERVAL = 100;
|
|
2314
2349
|
const MAX_INTERVAL = 800;
|
|
2315
2350
|
const clampedInterval = clamp(interval, MIN_INTERVAL, MAX_INTERVAL);
|
|
@@ -2327,38 +2362,33 @@ function computeLinePosYSpringParams(input) {
|
|
|
2327
2362
|
};
|
|
2328
2363
|
}
|
|
2329
2364
|
/**
|
|
2330
|
-
*
|
|
2365
|
+
* 计算一组歌词在当前布局中的视觉呈现参数。
|
|
2331
2366
|
*
|
|
2332
2367
|
* 根据播放状态、缓冲状态、布局模式与间奏信息,
|
|
2333
|
-
*
|
|
2368
|
+
* 生成一组歌词最终应使用的活跃状态、不透明度与模糊值。
|
|
2334
2369
|
*/
|
|
2335
|
-
function
|
|
2336
|
-
const {
|
|
2337
|
-
const isActive = hasBuffered ||
|
|
2370
|
+
function computeGroupPresentation(input) {
|
|
2371
|
+
const { groupIndex, scrollToIndex, latestIndex, hasBuffered, hidePassedLines, isPlaying, isNonDynamic, enableBlur, isUserScrolling, isCompact, interlude } = input;
|
|
2372
|
+
const isActive = hasBuffered || groupIndex >= scrollToIndex && groupIndex < latestIndex;
|
|
2338
2373
|
const blurLevel = computeLineBlur({
|
|
2339
2374
|
enableBlur,
|
|
2340
2375
|
isUserScrolling,
|
|
2341
2376
|
isActive,
|
|
2342
|
-
itemIndex:
|
|
2377
|
+
itemIndex: groupIndex,
|
|
2343
2378
|
scrollToIndex,
|
|
2344
2379
|
latestIndex,
|
|
2345
2380
|
isCompact
|
|
2346
2381
|
});
|
|
2347
2382
|
let targetOpacity;
|
|
2348
|
-
if (hidePassedLines) if (
|
|
2383
|
+
if (hidePassedLines) if (groupIndex < (interlude ? interlude.anchorLineIndex + 1 : scrollToIndex) && isPlaying) targetOpacity = 1e-4;
|
|
2349
2384
|
else if (hasBuffered) targetOpacity = .85;
|
|
2350
2385
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2351
2386
|
else if (hasBuffered) targetOpacity = .85;
|
|
2352
2387
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2353
|
-
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
2354
|
-
let targetScale = 100;
|
|
2355
|
-
if (!isActive && isPlaying) targetScale = line.isBG ? 75 : SCALE_ASPECT;
|
|
2356
2388
|
return {
|
|
2357
2389
|
isActive,
|
|
2358
2390
|
targetOpacity,
|
|
2359
|
-
|
|
2360
|
-
blurLevel,
|
|
2361
|
-
renderMode: isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID
|
|
2391
|
+
blurLevel
|
|
2362
2392
|
};
|
|
2363
2393
|
}
|
|
2364
2394
|
/**
|
|
@@ -2514,50 +2544,29 @@ const eqSet = (xs, ys) => xs.size === ys.size && [...xs].every((x) => ys.has(x))
|
|
|
2514
2544
|
* - 根据新的热行状态和已有的缓冲行状态,计算出应移除的缓冲行 ID
|
|
2515
2545
|
*/
|
|
2516
2546
|
function computePlayerTimeState(input) {
|
|
2517
|
-
const { time,
|
|
2518
|
-
const
|
|
2547
|
+
const { time, currentGroups, timelineState: { hotGroups, bufferedGroups } } = input;
|
|
2548
|
+
const nextHotGroups = new Set(hotGroups);
|
|
2519
2549
|
const addedIds = /* @__PURE__ */ new Set();
|
|
2520
2550
|
const removedHotIds = /* @__PURE__ */ new Set();
|
|
2521
2551
|
const removedBufferedIds = /* @__PURE__ */ new Set();
|
|
2522
|
-
for (const lastHotId of
|
|
2523
|
-
const
|
|
2524
|
-
if (!
|
|
2525
|
-
|
|
2526
|
-
removedHotIds.add(lastHotId);
|
|
2527
|
-
continue;
|
|
2528
|
-
}
|
|
2529
|
-
if (line.isBG) continue;
|
|
2530
|
-
const nextLine = processedLines[lastHotId + 1];
|
|
2531
|
-
if (nextLine?.isBG) {
|
|
2532
|
-
const nextMainLine = processedLines[lastHotId + 2];
|
|
2533
|
-
const startTime = Math.min(line.startTime, nextLine.startTime);
|
|
2534
|
-
const endTime = Math.min(Math.max(line.endTime, nextMainLine?.startTime ?? Number.MAX_VALUE), Math.max(line.endTime, nextLine.endTime));
|
|
2535
|
-
if (time < startTime || endTime <= time) {
|
|
2536
|
-
nextHotLines.delete(lastHotId);
|
|
2537
|
-
removedHotIds.add(lastHotId);
|
|
2538
|
-
nextHotLines.delete(lastHotId + 1);
|
|
2539
|
-
removedHotIds.add(lastHotId + 1);
|
|
2540
|
-
}
|
|
2541
|
-
} else if (time < line.startTime || line.endTime <= time) {
|
|
2542
|
-
nextHotLines.delete(lastHotId);
|
|
2552
|
+
for (const lastHotId of hotGroups) {
|
|
2553
|
+
const group = currentGroups[lastHotId];
|
|
2554
|
+
if (!group || time < group.startTime || group.endTime <= time) {
|
|
2555
|
+
nextHotGroups.delete(lastHotId);
|
|
2543
2556
|
removedHotIds.add(lastHotId);
|
|
2544
2557
|
}
|
|
2545
2558
|
}
|
|
2546
|
-
for (let id = 0; id <
|
|
2547
|
-
const
|
|
2548
|
-
if (!
|
|
2549
|
-
if (
|
|
2550
|
-
|
|
2559
|
+
for (let id = 0; id < currentGroups.length; id++) {
|
|
2560
|
+
const group = currentGroups[id];
|
|
2561
|
+
if (!group) continue;
|
|
2562
|
+
if (group.startTime <= time && group.endTime > time && !nextHotGroups.has(id)) {
|
|
2563
|
+
nextHotGroups.add(id);
|
|
2551
2564
|
addedIds.add(id);
|
|
2552
|
-
if (processedLines[id + 1]?.isBG) {
|
|
2553
|
-
nextHotLines.add(id + 1);
|
|
2554
|
-
addedIds.add(id + 1);
|
|
2555
|
-
}
|
|
2556
2565
|
}
|
|
2557
2566
|
}
|
|
2558
|
-
for (const id of
|
|
2567
|
+
for (const id of bufferedGroups) if (!nextHotGroups.has(id)) removedBufferedIds.add(id);
|
|
2559
2568
|
return {
|
|
2560
|
-
|
|
2569
|
+
nextHotGroups,
|
|
2561
2570
|
addedIds,
|
|
2562
2571
|
removedHotIds,
|
|
2563
2572
|
removedBufferedIds
|
|
@@ -2569,10 +2578,10 @@ function computePlayerTimeState(input) {
|
|
|
2569
2578
|
* 若当前仍存在缓冲行,则优先对齐到最靠前的缓冲行;
|
|
2570
2579
|
* 否则对齐到第一条开始时间不小于当前时间的歌词行。
|
|
2571
2580
|
*/
|
|
2572
|
-
function pickScrollToIndexForSeek(time,
|
|
2573
|
-
if (
|
|
2574
|
-
const foundIndex =
|
|
2575
|
-
return foundIndex === -1 ?
|
|
2581
|
+
function pickScrollToIndexForSeek(time, currentGroups, bufferedGroups) {
|
|
2582
|
+
if (bufferedGroups.size > 0) return Math.min(...bufferedGroups);
|
|
2583
|
+
const foundIndex = currentGroups.findIndex((group) => group.startTime >= time);
|
|
2584
|
+
return foundIndex === -1 ? currentGroups.length : foundIndex;
|
|
2576
2585
|
}
|
|
2577
2586
|
/**
|
|
2578
2587
|
* 提交时间线状态转移的纯函数。
|
|
@@ -2582,45 +2591,45 @@ function pickScrollToIndexForSeek(time, processedLines, bufferedLines) {
|
|
|
2582
2591
|
* 是否需要重置用户滚动状态、是否需要触发布局。
|
|
2583
2592
|
*/
|
|
2584
2593
|
function commitPlayerTimeState(input) {
|
|
2585
|
-
const { timelineState, time,
|
|
2594
|
+
const { timelineState, time, currentGroups, hasBottomContent, stateResult } = input;
|
|
2586
2595
|
const { addedIds, removedHotIds, removedBufferedIds } = stateResult;
|
|
2587
2596
|
const { isSeeking } = timelineState;
|
|
2588
2597
|
timelineState.currentTime = time;
|
|
2589
|
-
timelineState.
|
|
2598
|
+
timelineState.hotGroups = stateResult.nextHotGroups;
|
|
2590
2599
|
let shouldLayout = false;
|
|
2591
2600
|
let shouldResetScroll = false;
|
|
2592
|
-
const
|
|
2593
|
-
const
|
|
2601
|
+
const groupsToEnable = [];
|
|
2602
|
+
const groupsToDisable = /* @__PURE__ */ new Set();
|
|
2594
2603
|
if (isSeeking) {
|
|
2595
|
-
timelineState.
|
|
2596
|
-
timelineState.scrollToIndex = pickScrollToIndexForSeek(time,
|
|
2597
|
-
for (const id of removedHotIds)
|
|
2598
|
-
for (const id of timelineState.
|
|
2599
|
-
for (const id of removedBufferedIds)
|
|
2604
|
+
timelineState.bufferedGroups = new Set([...timelineState.hotGroups]);
|
|
2605
|
+
timelineState.scrollToIndex = pickScrollToIndexForSeek(time, currentGroups, timelineState.bufferedGroups);
|
|
2606
|
+
for (const id of removedHotIds) groupsToDisable.add(id);
|
|
2607
|
+
for (const id of timelineState.hotGroups) groupsToEnable.push(id);
|
|
2608
|
+
for (const id of removedBufferedIds) groupsToDisable.add(id);
|
|
2600
2609
|
shouldResetScroll = true;
|
|
2601
2610
|
shouldLayout = true;
|
|
2602
2611
|
} else if (addedIds.size > 0) {
|
|
2603
2612
|
for (const id of addedIds) {
|
|
2604
|
-
timelineState.
|
|
2605
|
-
|
|
2613
|
+
timelineState.bufferedGroups.add(id);
|
|
2614
|
+
groupsToEnable.push(id);
|
|
2606
2615
|
}
|
|
2607
2616
|
for (const id of removedBufferedIds) {
|
|
2608
|
-
timelineState.
|
|
2609
|
-
|
|
2617
|
+
timelineState.bufferedGroups.delete(id);
|
|
2618
|
+
groupsToDisable.add(id);
|
|
2610
2619
|
}
|
|
2611
|
-
if (timelineState.
|
|
2620
|
+
if (timelineState.bufferedGroups.size > 0) timelineState.scrollToIndex = Math.min(...timelineState.bufferedGroups);
|
|
2612
2621
|
shouldLayout = true;
|
|
2613
|
-
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.
|
|
2614
|
-
for (const id of timelineState.
|
|
2615
|
-
if (timelineState.
|
|
2616
|
-
timelineState.
|
|
2617
|
-
|
|
2622
|
+
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.bufferedGroups)) {
|
|
2623
|
+
for (const id of timelineState.bufferedGroups) {
|
|
2624
|
+
if (timelineState.hotGroups.has(id)) continue;
|
|
2625
|
+
timelineState.bufferedGroups.delete(id);
|
|
2626
|
+
groupsToDisable.add(id);
|
|
2618
2627
|
}
|
|
2619
2628
|
shouldLayout = true;
|
|
2620
2629
|
}
|
|
2621
|
-
if (timelineState.
|
|
2622
|
-
if (time >=
|
|
2623
|
-
const targetIndex = hasBottomContent ?
|
|
2630
|
+
if (timelineState.bufferedGroups.size === 0 && currentGroups.length > 0) {
|
|
2631
|
+
if (time >= currentGroups[currentGroups.length - 1].endTime) {
|
|
2632
|
+
const targetIndex = hasBottomContent ? currentGroups.length : currentGroups.length - 1;
|
|
2624
2633
|
if (timelineState.scrollToIndex !== targetIndex) {
|
|
2625
2634
|
timelineState.scrollToIndex = targetIndex;
|
|
2626
2635
|
shouldLayout = true;
|
|
@@ -2631,8 +2640,8 @@ function commitPlayerTimeState(input) {
|
|
|
2631
2640
|
return {
|
|
2632
2641
|
shouldLayout,
|
|
2633
2642
|
shouldResetScroll,
|
|
2634
|
-
|
|
2635
|
-
|
|
2643
|
+
groupsToEnable,
|
|
2644
|
+
groupsToDisable: [...groupsToDisable]
|
|
2636
2645
|
};
|
|
2637
2646
|
}
|
|
2638
2647
|
//#endregion
|
|
@@ -2647,17 +2656,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2647
2656
|
timelineState = {
|
|
2648
2657
|
currentTime: 0,
|
|
2649
2658
|
lastCurrentTime: 0,
|
|
2650
|
-
|
|
2651
|
-
|
|
2659
|
+
hotGroups: /* @__PURE__ */ new Set(),
|
|
2660
|
+
bufferedGroups: /* @__PURE__ */ new Set(),
|
|
2652
2661
|
scrollToIndex: 0,
|
|
2653
2662
|
isSeeking: false,
|
|
2654
2663
|
isPlaying: true,
|
|
2655
2664
|
initialLayoutFinished: false
|
|
2656
2665
|
};
|
|
2657
2666
|
/** @internal */
|
|
2658
|
-
|
|
2659
|
-
/** @internal */
|
|
2660
|
-
lyricLineElementMap = /* @__PURE__ */ new WeakMap();
|
|
2667
|
+
lyricGroupElementMap = /* @__PURE__ */ new WeakMap();
|
|
2661
2668
|
currentLyricLines = [];
|
|
2662
2669
|
processedLines = [];
|
|
2663
2670
|
lyricLinesIndexes = /* @__PURE__ */ new WeakMap();
|
|
@@ -2689,10 +2696,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2689
2696
|
isScrolled: false,
|
|
2690
2697
|
isUserScrolling: false
|
|
2691
2698
|
};
|
|
2692
|
-
|
|
2699
|
+
currentLyricGroups = [];
|
|
2700
|
+
lyricGroupSize = /* @__PURE__ */ new WeakMap();
|
|
2693
2701
|
size = [0, 0];
|
|
2694
2702
|
isPageVisible = true;
|
|
2695
2703
|
optimizeOptions = {};
|
|
2704
|
+
/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */
|
|
2705
|
+
alwaysPostpositionBackground = false;
|
|
2696
2706
|
posXSpringParams = {
|
|
2697
2707
|
mass: 1,
|
|
2698
2708
|
damping: 10,
|
|
@@ -2742,13 +2752,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2742
2752
|
shouldRelayout = true;
|
|
2743
2753
|
}
|
|
2744
2754
|
} else {
|
|
2745
|
-
const
|
|
2746
|
-
if (
|
|
2755
|
+
const groupObj = this.lyricGroupElementMap.get(entry.target);
|
|
2756
|
+
if (groupObj) {
|
|
2747
2757
|
const newSize = [entry.target.clientWidth, entry.target.clientHeight];
|
|
2748
|
-
const oldSize = this.
|
|
2758
|
+
const oldSize = this.lyricGroupSize.get(groupObj) ?? [0, 0];
|
|
2749
2759
|
if (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {
|
|
2750
|
-
this.
|
|
2751
|
-
|
|
2760
|
+
this.lyricGroupSize.set(groupObj, newSize);
|
|
2761
|
+
groupObj.onLineSizeChange(newSize);
|
|
2752
2762
|
shouldRelayout = true;
|
|
2753
2763
|
}
|
|
2754
2764
|
}
|
|
@@ -2874,7 +2884,7 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2874
2884
|
}
|
|
2875
2885
|
}
|
|
2876
2886
|
rebuildLyricLines() {
|
|
2877
|
-
for (const
|
|
2887
|
+
for (const group of this.currentLyricGroups) group.rebuildAllLines();
|
|
2878
2888
|
}
|
|
2879
2889
|
/**
|
|
2880
2890
|
* 根据当前配置处理不雅用语单词
|
|
@@ -2976,11 +2986,11 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2976
2986
|
break;
|
|
2977
2987
|
}
|
|
2978
2988
|
this.hasDuetLine = this.processedLines.some((line) => line.isDuet);
|
|
2979
|
-
for (const
|
|
2989
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
2990
|
+
this.currentLyricGroups = [];
|
|
2980
2991
|
this.interludeDots.setInterlude(void 0);
|
|
2981
|
-
this.timelineState.
|
|
2982
|
-
this.timelineState.
|
|
2983
|
-
this.setCurrentTime(0, true);
|
|
2992
|
+
this.timelineState.hotGroups.clear();
|
|
2993
|
+
this.timelineState.bufferedGroups.clear();
|
|
2984
2994
|
if (process.env.NODE_ENV !== "production") console.log("歌词处理完成", this);
|
|
2985
2995
|
}
|
|
2986
2996
|
/**
|
|
@@ -3006,19 +3016,19 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3006
3016
|
if (!timelineState.initialLayoutFinished && !timelineState.isSeeking) return;
|
|
3007
3017
|
const stateResult = computePlayerTimeState({
|
|
3008
3018
|
time,
|
|
3009
|
-
|
|
3019
|
+
currentGroups: this.currentLyricGroups,
|
|
3010
3020
|
timelineState
|
|
3011
3021
|
});
|
|
3012
3022
|
const hasBottomContent = this.bottomLine.getElement().innerHTML.trim().length > 0;
|
|
3013
3023
|
const commitResult = commitPlayerTimeState({
|
|
3014
3024
|
timelineState,
|
|
3015
3025
|
time,
|
|
3016
|
-
|
|
3026
|
+
currentGroups: this.currentLyricGroups,
|
|
3017
3027
|
hasBottomContent,
|
|
3018
3028
|
stateResult
|
|
3019
3029
|
});
|
|
3020
|
-
for (const id of commitResult.
|
|
3021
|
-
for (const id of commitResult.
|
|
3030
|
+
for (const id of commitResult.groupsToDisable) this.currentLyricGroups[id]?.disable();
|
|
3031
|
+
for (const id of commitResult.groupsToEnable) this.currentLyricGroups[id]?.enable();
|
|
3022
3032
|
if (commitResult.shouldResetScroll) this.resetScroll();
|
|
3023
3033
|
if (commitResult.shouldLayout) this.calcLayout();
|
|
3024
3034
|
}
|
|
@@ -3043,14 +3053,14 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3043
3053
|
const interlude = computeCurrentInterlude({
|
|
3044
3054
|
currentTime: this.timelineState.currentTime,
|
|
3045
3055
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3046
|
-
|
|
3056
|
+
currentGroups: this.currentLyricGroups
|
|
3047
3057
|
});
|
|
3048
3058
|
const isInterludeActive = !!interlude;
|
|
3049
3059
|
if (this.layoutState.targetAlignIndex !== this.timelineState.scrollToIndex || this.layoutState.lastInterludeState !== isInterludeActive) {
|
|
3050
3060
|
this.layoutState.lastInterludeState = isInterludeActive;
|
|
3051
3061
|
const springParams = computeLinePosYSpringParams({
|
|
3052
3062
|
enabled: this.getEnableSpring(),
|
|
3053
|
-
|
|
3063
|
+
currentGroups: this.currentLyricGroups,
|
|
3054
3064
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3055
3065
|
isSeeking: this.timelineState.isSeeking,
|
|
3056
3066
|
isInterludeActive
|
|
@@ -3068,17 +3078,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3068
3078
|
if (interlude.anchorLineIndex !== -1) curPos -= totalInterludeHeight;
|
|
3069
3079
|
}
|
|
3070
3080
|
const LINE_HEIGHT_FALLBACK = this.size[1] / 5;
|
|
3071
|
-
const scrollOffset = this.
|
|
3081
|
+
const scrollOffset = this.currentLyricGroups.slice(0, targetAlignIndex).reduce((acc, group) => acc + (this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK), 0);
|
|
3072
3082
|
this.scrollState.scrollBoundary.minOffset = -scrollOffset;
|
|
3073
3083
|
curPos -= scrollOffset;
|
|
3074
3084
|
curPos += this.size[1] * this.layoutState.alignPosition;
|
|
3075
|
-
const
|
|
3085
|
+
const curGroup = this.currentLyricGroups[targetAlignIndex];
|
|
3076
3086
|
this.layoutState.targetAlignIndex = targetAlignIndex;
|
|
3077
|
-
const isBottomFocused = targetAlignIndex === this.
|
|
3087
|
+
const isBottomFocused = targetAlignIndex === this.currentLyricGroups.length;
|
|
3078
3088
|
this.bottomLine.setFocused(isBottomFocused);
|
|
3079
|
-
|
|
3080
|
-
if (curLine) targetLineHeight = this.lyricLinesSize.get(curLine)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3081
|
-
else if (isBottomFocused) targetLineHeight = this.bottomLine.lineSize[1];
|
|
3089
|
+
const targetLineHeight = curGroup ? this.lyricGroupSize.get(curGroup)?.[1] ?? LINE_HEIGHT_FALLBACK : isBottomFocused ? this.bottomLine.lineSize[1] : 0;
|
|
3082
3090
|
if (targetLineHeight > 0) switch (this.layoutState.alignAnchor) {
|
|
3083
3091
|
case LayoutAlignAnchor.Bottom:
|
|
3084
3092
|
curPos -= targetLineHeight;
|
|
@@ -3088,13 +3096,12 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3088
3096
|
break;
|
|
3089
3097
|
case LayoutAlignAnchor.Top: break;
|
|
3090
3098
|
}
|
|
3091
|
-
const latestIndex = Math.max(...this.timelineState.
|
|
3099
|
+
const latestIndex = Math.max(...this.timelineState.bufferedGroups);
|
|
3092
3100
|
let delay = 0;
|
|
3093
3101
|
let baseDelay = sync ? 0 : .05;
|
|
3094
3102
|
let setDots = false;
|
|
3095
|
-
this.
|
|
3096
|
-
const hasBuffered = this.timelineState.
|
|
3097
|
-
const line = lineObj.getLine();
|
|
3103
|
+
this.currentLyricGroups.forEach((group, i) => {
|
|
3104
|
+
const hasBuffered = this.timelineState.bufferedGroups.has(i);
|
|
3098
3105
|
const shouldShowDots = interlude && i === interlude.anchorLineIndex + 1;
|
|
3099
3106
|
if (!setDots && shouldShowDots) {
|
|
3100
3107
|
setDots = true;
|
|
@@ -3106,31 +3113,28 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3106
3113
|
curPos += this.layoutState.interludeDotsSize[1];
|
|
3107
3114
|
curPos += dotMargin;
|
|
3108
3115
|
}
|
|
3109
|
-
const presentation =
|
|
3110
|
-
|
|
3111
|
-
lineIndex: i,
|
|
3116
|
+
const presentation = computeGroupPresentation({
|
|
3117
|
+
groupIndex: i,
|
|
3112
3118
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3113
3119
|
latestIndex,
|
|
3114
3120
|
hasBuffered,
|
|
3115
3121
|
hidePassedLines: this.hidePassedLines,
|
|
3116
3122
|
isPlaying: this.timelineState.isPlaying,
|
|
3117
3123
|
isNonDynamic: this.isNonDynamic,
|
|
3118
|
-
enableScale: this.enableScale,
|
|
3119
3124
|
enableBlur: this.enableBlur,
|
|
3120
3125
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
3121
3126
|
isCompact: window.innerWidth <= 1024,
|
|
3122
3127
|
interlude
|
|
3123
3128
|
});
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
else if (!line.isBG) curPos += this.lyricLinesSize.get(lineObj)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3129
|
+
group.setTransform(curPos, force, delay, presentation.isActive, presentation.targetOpacity, presentation.blurLevel);
|
|
3130
|
+
curPos += this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3127
3131
|
if (curPos >= 0 && !this.timelineState.isSeeking) {
|
|
3128
|
-
|
|
3132
|
+
delay += baseDelay;
|
|
3129
3133
|
if (i >= this.timelineState.scrollToIndex) baseDelay /= 1.05;
|
|
3130
3134
|
}
|
|
3131
3135
|
});
|
|
3132
3136
|
this.scrollState.scrollBoundary.maxOffset = curPos + this.scrollState.scrollOffset - this.size[1] / 2;
|
|
3133
|
-
const bottomIndex = this.
|
|
3137
|
+
const bottomIndex = this.currentLyricGroups.length;
|
|
3134
3138
|
const finalBottomBlur = computeLineBlur({
|
|
3135
3139
|
enableBlur: this.enableBlur,
|
|
3136
3140
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
@@ -3160,7 +3164,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3160
3164
|
...params
|
|
3161
3165
|
};
|
|
3162
3166
|
this.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);
|
|
3163
|
-
for (const
|
|
3167
|
+
for (const group of this.currentLyricGroups) {
|
|
3168
|
+
group.posY.updateParams(this.posYSpringParams);
|
|
3169
|
+
group.bgSlideY.updateParams(this.posYSpringParams);
|
|
3170
|
+
}
|
|
3164
3171
|
}
|
|
3165
3172
|
/**
|
|
3166
3173
|
* 设置所有歌词行在缩放大小上的弹簧属性,包括重量、弹力和阻力。
|
|
@@ -3176,8 +3183,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3176
3183
|
...this.scaleForBGSpringParams,
|
|
3177
3184
|
...params
|
|
3178
3185
|
};
|
|
3179
|
-
for (const
|
|
3180
|
-
|
|
3186
|
+
for (const group of this.currentLyricGroups) {
|
|
3187
|
+
group.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);
|
|
3188
|
+
group.bgLine?.lineTransforms.scale.updateParams(this.scaleForBGSpringParams);
|
|
3189
|
+
}
|
|
3181
3190
|
}
|
|
3182
3191
|
/**
|
|
3183
3192
|
* 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来
|
|
@@ -3249,6 +3258,23 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3249
3258
|
getCurrentTime() {
|
|
3250
3259
|
return this.timelineState.currentTime;
|
|
3251
3260
|
}
|
|
3261
|
+
/**
|
|
3262
|
+
* 设置是否让背景人声行始终后置显示
|
|
3263
|
+
*
|
|
3264
|
+
* 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;
|
|
3265
|
+
* 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示
|
|
3266
|
+
* @param enable 是否启用始终后置
|
|
3267
|
+
*/
|
|
3268
|
+
setAlwaysPostpositionBackground(enable) {
|
|
3269
|
+
if (this.alwaysPostpositionBackground === enable) return;
|
|
3270
|
+
this.alwaysPostpositionBackground = enable;
|
|
3271
|
+
this.rebuildLyricLines();
|
|
3272
|
+
this.calcLayout();
|
|
3273
|
+
}
|
|
3274
|
+
/** 获取当前是否设置了让背景人声行始终后置显示 */
|
|
3275
|
+
getAlwaysPostpositionBackground() {
|
|
3276
|
+
return this.alwaysPostpositionBackground;
|
|
3277
|
+
}
|
|
3252
3278
|
getElement() {
|
|
3253
3279
|
return this.element;
|
|
3254
3280
|
}
|
|
@@ -3259,6 +3285,194 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3259
3285
|
}
|
|
3260
3286
|
};
|
|
3261
3287
|
//#endregion
|
|
3288
|
+
//#region src/lyric-player/base/group.ts
|
|
3289
|
+
var LyricLineGroupBase = class {
|
|
3290
|
+
mainLine;
|
|
3291
|
+
bgLine;
|
|
3292
|
+
posY = new Spring(0);
|
|
3293
|
+
bgSlideY = new Spring(-80);
|
|
3294
|
+
top = 0;
|
|
3295
|
+
delay = 0;
|
|
3296
|
+
isActive = false;
|
|
3297
|
+
opacity = 1;
|
|
3298
|
+
blur = 0;
|
|
3299
|
+
isBgFirst = false;
|
|
3300
|
+
constructor(mainLine, bgLine) {
|
|
3301
|
+
this.mainLine = mainLine;
|
|
3302
|
+
this.bgLine = bgLine;
|
|
3303
|
+
}
|
|
3304
|
+
get startTime() {
|
|
3305
|
+
return this.mainLine.getLine().startTime;
|
|
3306
|
+
}
|
|
3307
|
+
get endTime() {
|
|
3308
|
+
return this.mainLine.getLine().endTime;
|
|
3309
|
+
}
|
|
3310
|
+
onLineSizeChange(size) {
|
|
3311
|
+
this.mainLine.onLineSizeChange(size);
|
|
3312
|
+
this.bgLine?.onLineSizeChange(size);
|
|
3313
|
+
}
|
|
3314
|
+
setTransform(top, force, delay, isActive, opacity, blur) {
|
|
3315
|
+
this.top = top;
|
|
3316
|
+
this.delay = delay;
|
|
3317
|
+
this.isActive = isActive;
|
|
3318
|
+
this.opacity = opacity;
|
|
3319
|
+
this.blur = blur;
|
|
3320
|
+
this.setLineTransformations(force, delay);
|
|
3321
|
+
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
3322
|
+
const hiddenSlideY = (this.lyricPlayer.getAlwaysPostpositionBackground() ? false : this.isBgFirst) ? 80 : -80;
|
|
3323
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3324
|
+
const targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;
|
|
3325
|
+
if (force || !enableSpring) {
|
|
3326
|
+
this.posY.setPosition(top);
|
|
3327
|
+
this.bgSlideY.setPosition(targetBgSlideY);
|
|
3328
|
+
this.renderStyles();
|
|
3329
|
+
} else {
|
|
3330
|
+
this.posY.setTargetPosition(top, delay);
|
|
3331
|
+
this.bgSlideY.setTargetPosition(targetBgSlideY, delay);
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
setLineTransformations(force, delay) {
|
|
3335
|
+
const enableScale = this.lyricPlayer.getEnableScale();
|
|
3336
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3337
|
+
const renderMode = this.isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID;
|
|
3338
|
+
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
3339
|
+
let mainScale = 100;
|
|
3340
|
+
if (!this.isActive && isPlaying) mainScale = SCALE_ASPECT;
|
|
3341
|
+
this.mainLine.setTransform(mainScale, 1, 0, force, delay, renderMode);
|
|
3342
|
+
let bgScale = 100;
|
|
3343
|
+
if (!this.isActive && isPlaying) bgScale = 75;
|
|
3344
|
+
this.bgLine?.setTransform(bgScale, 1, 0, force, delay, renderMode);
|
|
3345
|
+
}
|
|
3346
|
+
update(delta) {
|
|
3347
|
+
if (this.lyricPlayer.getEnableSpring()) {
|
|
3348
|
+
this.posY.update(delta);
|
|
3349
|
+
this.bgSlideY.update(delta);
|
|
3350
|
+
this.renderStyles();
|
|
3351
|
+
}
|
|
3352
|
+
this.mainLine.update(delta);
|
|
3353
|
+
this.bgLine?.update(delta);
|
|
3354
|
+
}
|
|
3355
|
+
rebuildAllLines() {
|
|
3356
|
+
this.mainLine.rebuildElement();
|
|
3357
|
+
this.bgLine?.rebuildElement();
|
|
3358
|
+
}
|
|
3359
|
+
enable(time, shouldPlay) {
|
|
3360
|
+
this.mainLine.enable(time, shouldPlay);
|
|
3361
|
+
this.bgLine?.enable(time, shouldPlay);
|
|
3362
|
+
}
|
|
3363
|
+
disable() {
|
|
3364
|
+
this.mainLine.disable();
|
|
3365
|
+
this.bgLine?.disable();
|
|
3366
|
+
}
|
|
3367
|
+
dispose() {
|
|
3368
|
+
this.mainLine.dispose();
|
|
3369
|
+
this.bgLine?.dispose();
|
|
3370
|
+
}
|
|
3371
|
+
};
|
|
3372
|
+
//#endregion
|
|
3373
|
+
//#region src/lyric-player/dom/lyric-group.ts
|
|
3374
|
+
var LyricLineGroup = class extends LyricLineGroupBase {
|
|
3375
|
+
lyricPlayer;
|
|
3376
|
+
element;
|
|
3377
|
+
bgWrapper;
|
|
3378
|
+
lastIsActive;
|
|
3379
|
+
constructor(lyricPlayer, mainLine) {
|
|
3380
|
+
super(mainLine);
|
|
3381
|
+
this.lyricPlayer = lyricPlayer;
|
|
3382
|
+
this.element = document.createElement("div");
|
|
3383
|
+
this.element.className = lyric_player_module_default.lyricLineWrapper;
|
|
3384
|
+
this.element.appendChild(mainLine.getElement());
|
|
3385
|
+
this.posY.setPosition(window.innerHeight * 2);
|
|
3386
|
+
lyricPlayer.resizeObserver.observe(this.element);
|
|
3387
|
+
}
|
|
3388
|
+
get isInSight() {
|
|
3389
|
+
const t = this.posY.getCurrentPosition();
|
|
3390
|
+
let h = this.lyricPlayer.lyricGroupSize?.get(this)?.[1];
|
|
3391
|
+
if (h === void 0 || h === 0) h = this.element.clientHeight || 0;
|
|
3392
|
+
const pb = this.lyricPlayer.size[1];
|
|
3393
|
+
const ov = this.lyricPlayer.getOverscanPx();
|
|
3394
|
+
return !(t > pb + h + ov || t < -h - ov);
|
|
3395
|
+
}
|
|
3396
|
+
show() {
|
|
3397
|
+
if (!this.element.parentElement) {
|
|
3398
|
+
const playerEl = this.lyricPlayer.getElement();
|
|
3399
|
+
const groups = this.lyricPlayer.currentLyricGroups;
|
|
3400
|
+
const myIndex = groups.indexOf(this);
|
|
3401
|
+
let referenceNode = null;
|
|
3402
|
+
if (myIndex !== -1) {
|
|
3403
|
+
for (let i = myIndex + 1; i < groups.length; i++) if (groups[i].element.parentElement === playerEl) {
|
|
3404
|
+
referenceNode = groups[i].element;
|
|
3405
|
+
break;
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
playerEl.insertBefore(this.element, referenceNode);
|
|
3409
|
+
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3410
|
+
}
|
|
3411
|
+
this.mainLine.show();
|
|
3412
|
+
this.bgLine?.show();
|
|
3413
|
+
}
|
|
3414
|
+
hide() {
|
|
3415
|
+
if (this.element.parentElement) {
|
|
3416
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3417
|
+
this.element.remove();
|
|
3418
|
+
this.mainLine.teardownContent();
|
|
3419
|
+
this.bgLine?.teardownContent();
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
update(delta) {
|
|
3423
|
+
if (this.isInSight) this.show();
|
|
3424
|
+
else this.hide();
|
|
3425
|
+
super.update(delta);
|
|
3426
|
+
}
|
|
3427
|
+
addBgLine(bgLine) {
|
|
3428
|
+
if (this.bgLine) this.bgLine.dispose();
|
|
3429
|
+
if (this.bgWrapper) this.bgWrapper.remove();
|
|
3430
|
+
this.bgLine = bgLine;
|
|
3431
|
+
const bgStartTime = bgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;
|
|
3432
|
+
const mainStartTime = this.mainLine.getLine().words[0]?.startTime ?? this.mainLine.getLine().startTime;
|
|
3433
|
+
this.isBgFirst = bgStartTime < mainStartTime;
|
|
3434
|
+
if (this.mainLine.getLine().isDuet) bgLine.getElement().classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3435
|
+
this.bgWrapper = document.createElement("div");
|
|
3436
|
+
this.bgWrapper.className = lyric_player_module_default.bgWrapper;
|
|
3437
|
+
this.bgWrapper.appendChild(bgLine.getElement());
|
|
3438
|
+
if (!this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst) {
|
|
3439
|
+
this.bgWrapper.classList.add(lyric_player_module_default.bgWrapperTop);
|
|
3440
|
+
this.element.insertBefore(this.bgWrapper, this.mainLine.getElement());
|
|
3441
|
+
this.bgSlideY.setPosition(80);
|
|
3442
|
+
} else this.element.appendChild(this.bgWrapper);
|
|
3443
|
+
}
|
|
3444
|
+
renderStyles() {
|
|
3445
|
+
const y = this.posY.getCurrentPosition().toFixed(1);
|
|
3446
|
+
this.element.style.transform = `translateY(${y}px)`;
|
|
3447
|
+
this.element.style.opacity = this.opacity.toString();
|
|
3448
|
+
this.element.style.filter = `blur(${Math.min(5, this.blur)}px)`;
|
|
3449
|
+
if (!this.lyricPlayer.getEnableSpring()) this.element.style.transitionDelay = `${this.delay}ms`;
|
|
3450
|
+
if (this.bgWrapper) {
|
|
3451
|
+
if (this.lastIsActive !== this.isActive) {
|
|
3452
|
+
this.lastIsActive = this.isActive;
|
|
3453
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperActive, this.isActive);
|
|
3454
|
+
}
|
|
3455
|
+
const slideY = this.bgSlideY.getCurrentPosition();
|
|
3456
|
+
const slideYStr = slideY.toFixed(1);
|
|
3457
|
+
const activeProgress = clamp01(1 - Math.abs(slideY) / 80);
|
|
3458
|
+
const scaleStr = (.8 + activeProgress * .2).toFixed(3);
|
|
3459
|
+
this.bgWrapper.style.transform = `translateY(${slideYStr}%) scale(${scaleStr})`;
|
|
3460
|
+
const shouldBgFirst = !this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst;
|
|
3461
|
+
if (shouldBgFirst) {
|
|
3462
|
+
const currentMarginTop = -(this.bgWrapper.clientHeight || 0) * (1 - activeProgress);
|
|
3463
|
+
this.bgWrapper.style.marginTop = `${currentMarginTop.toFixed(1)}px`;
|
|
3464
|
+
} else this.bgWrapper.style.marginTop = "";
|
|
3465
|
+
const isHidden = slideYStr === (shouldBgFirst ? "80.0" : "-80.0") && !this.isActive;
|
|
3466
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperHidden, isHidden);
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
dispose() {
|
|
3470
|
+
super.dispose();
|
|
3471
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3472
|
+
this.element.remove();
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3475
|
+
//#endregion
|
|
3262
3476
|
//#region src/utils/is-cjk.ts
|
|
3263
3477
|
const isCJK = (char) => {
|
|
3264
3478
|
return /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u.test(char);
|
|
@@ -3275,10 +3489,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3275
3489
|
blur = 0;
|
|
3276
3490
|
opacity = 1;
|
|
3277
3491
|
delay = 0;
|
|
3278
|
-
lineTransforms = {
|
|
3279
|
-
posY: new Spring(0),
|
|
3280
|
-
scale: new Spring(100)
|
|
3281
|
-
};
|
|
3492
|
+
lineTransforms = { scale: new Spring(100) };
|
|
3282
3493
|
/**
|
|
3283
3494
|
* 用于 CJK 词语边界检测的分词器
|
|
3284
3495
|
*/
|
|
@@ -3288,9 +3499,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3288
3499
|
* 用于正确处理 emoji、复合字符等
|
|
3289
3500
|
*/
|
|
3290
3501
|
static graphemeSegmenter = typeof Intl !== "undefined" && Intl.Segmenter ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
3291
|
-
|
|
3292
|
-
setTransform(top = this.top, scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3293
|
-
this.top = top;
|
|
3502
|
+
setTransform(scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3294
3503
|
this.scale = scale;
|
|
3295
3504
|
this.opacity = opacity;
|
|
3296
3505
|
this.blur = blur;
|
|
@@ -3413,6 +3622,7 @@ function getMeasurementContext() {
|
|
|
3413
3622
|
* 用于平衡歌词行在换行后的各行长度
|
|
3414
3623
|
*/
|
|
3415
3624
|
var LineBalancer = class {
|
|
3625
|
+
mainElement;
|
|
3416
3626
|
isBalancing = false;
|
|
3417
3627
|
lastBalancedContainerWidth = -1;
|
|
3418
3628
|
constructor(mainElement) {
|
|
@@ -3736,13 +3946,9 @@ function generateFadeGradient(width, padding = 0, bright = "rgba(0,0,0,var(--bri
|
|
|
3736
3946
|
const leftPos = (1 - widthInTotal) / 2;
|
|
3737
3947
|
return [`linear-gradient(to right,${bright} ${leftPos * 100}%,${dark} ${(leftPos + widthInTotal) * 100}%)`, totalAspect];
|
|
3738
3948
|
}
|
|
3739
|
-
var RawLyricLineMouseEvent = class extends MouseEvent {
|
|
3740
|
-
constructor(line, event) {
|
|
3741
|
-
super(event.type, event);
|
|
3742
|
-
this.line = line;
|
|
3743
|
-
}
|
|
3744
|
-
};
|
|
3745
3949
|
var LyricLineEl = class extends LyricLineBase {
|
|
3950
|
+
lyricPlayer;
|
|
3951
|
+
lyricLine;
|
|
3746
3952
|
element = document.createElement("div");
|
|
3747
3953
|
splittedWords = [];
|
|
3748
3954
|
built = false;
|
|
@@ -3768,12 +3974,9 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3768
3974
|
super();
|
|
3769
3975
|
this.lyricPlayer = lyricPlayer;
|
|
3770
3976
|
this.lyricLine = lyricLine;
|
|
3771
|
-
this._prevParentEl = lyricPlayer.getElement();
|
|
3772
|
-
lyricPlayer.resizeObserver.observe(this.element);
|
|
3773
3977
|
this.element.setAttribute("class", lyric_player_module_default.lyricLine);
|
|
3774
3978
|
if (this.lyricLine.isBG) this.element.classList.add(lyric_player_module_default.lyricBgLine);
|
|
3775
3979
|
if (this.lyricLine.isDuet) this.element.classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3776
|
-
this.lineTransforms.posY.setPosition(window.innerHeight * 2);
|
|
3777
3980
|
this.element.appendChild(document.createElement("div"));
|
|
3778
3981
|
this.element.appendChild(document.createElement("div"));
|
|
3779
3982
|
this.element.appendChild(document.createElement("div"));
|
|
@@ -3786,33 +3989,6 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3786
3989
|
if (LyricLineBase.wordSegmenter) this.balancer = new LineBalancer(main);
|
|
3787
3990
|
this.rebuildStyle();
|
|
3788
3991
|
}
|
|
3789
|
-
listenersMap = /* @__PURE__ */ new Map();
|
|
3790
|
-
onMouseEvent = (e) => {
|
|
3791
|
-
const wrapped = new RawLyricLineMouseEvent(this, e);
|
|
3792
|
-
for (const listener of this.listenersMap.get(e.type) ?? []) listener.call(this, wrapped);
|
|
3793
|
-
if (!this.dispatchEvent(wrapped) || wrapped.defaultPrevented) {
|
|
3794
|
-
e.preventDefault();
|
|
3795
|
-
e.stopPropagation();
|
|
3796
|
-
e.stopImmediatePropagation();
|
|
3797
|
-
}
|
|
3798
|
-
};
|
|
3799
|
-
addMouseEventListener(type, callback, options) {
|
|
3800
|
-
if (callback) {
|
|
3801
|
-
const listeners = this.listenersMap.get(type) ?? /* @__PURE__ */ new Set();
|
|
3802
|
-
if (listeners.size === 0) this.element.addEventListener(type, this.onMouseEvent, options);
|
|
3803
|
-
listeners.add(callback);
|
|
3804
|
-
this.listenersMap.set(type, listeners);
|
|
3805
|
-
}
|
|
3806
|
-
}
|
|
3807
|
-
removeMouseEventListener(type, callback, options) {
|
|
3808
|
-
if (callback) {
|
|
3809
|
-
const listeners = this.listenersMap.get(type);
|
|
3810
|
-
if (listeners) {
|
|
3811
|
-
listeners.delete(callback);
|
|
3812
|
-
if (listeners.size === 0) this.element.removeEventListener(type, this.onMouseEvent, options);
|
|
3813
|
-
}
|
|
3814
|
-
}
|
|
3815
|
-
}
|
|
3816
3992
|
areWordsOnSameLine(word1, word2) {
|
|
3817
3993
|
if (word1?.mainElement && word2?.mainElement) {
|
|
3818
3994
|
const word1el = word1.mainElement;
|
|
@@ -3905,34 +4081,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3905
4081
|
getLine() {
|
|
3906
4082
|
return this.lyricLine;
|
|
3907
4083
|
}
|
|
3908
|
-
_prevParentEl;
|
|
3909
4084
|
lastStyle = "";
|
|
3910
4085
|
show() {
|
|
3911
|
-
if (!this.element.parentElement) {
|
|
3912
|
-
this._prevParentEl.appendChild(this.element);
|
|
3913
|
-
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3914
|
-
}
|
|
3915
4086
|
if (!this.built) {
|
|
3916
4087
|
this.rebuildElement();
|
|
3917
4088
|
this.built = true;
|
|
3918
4089
|
this.updateMaskImageSync();
|
|
3919
4090
|
}
|
|
3920
|
-
this.rebuildStyle();
|
|
3921
|
-
}
|
|
3922
|
-
hide() {
|
|
3923
|
-
if (this.element.parentElement) {
|
|
3924
|
-
this._prevParentEl.removeChild(this.element);
|
|
3925
|
-
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3926
|
-
}
|
|
3927
|
-
if (this.built) {
|
|
3928
|
-
this.disposeElements();
|
|
3929
|
-
this.built = false;
|
|
3930
|
-
}
|
|
3931
4091
|
}
|
|
3932
4092
|
rebuildStyle() {
|
|
3933
4093
|
let style = "";
|
|
3934
|
-
style += `transform:
|
|
3935
|
-
if (!this.lyricPlayer.getEnableSpring()
|
|
4094
|
+
style += `transform: scale(${(this.lineTransforms.scale.getCurrentPosition() / 100).toFixed(4)});`;
|
|
4095
|
+
if (!this.lyricPlayer.getEnableSpring()) style += `transition-delay:${this.delay}ms;`;
|
|
3936
4096
|
style += `filter:blur(${Math.min(5, this.blur)}px);`;
|
|
3937
4097
|
if (style !== this.lastStyle) {
|
|
3938
4098
|
this.lastStyle = style;
|
|
@@ -3945,7 +4105,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3945
4105
|
const trans = this.element.children[1];
|
|
3946
4106
|
const roman = this.element.children[2];
|
|
3947
4107
|
if (this.lyricPlayer._getIsNonDynamic()) {
|
|
3948
|
-
main.
|
|
4108
|
+
main.textContent = this.lyricLine.words.map((w) => this.lyricPlayer.processObsceneWord(w)).join("");
|
|
3949
4109
|
this.setSubLinesText(trans, roman);
|
|
3950
4110
|
return;
|
|
3951
4111
|
}
|
|
@@ -3958,8 +4118,8 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3958
4118
|
}
|
|
3959
4119
|
/** 设置翻译与音译行文本 */
|
|
3960
4120
|
setSubLinesText(trans, roman) {
|
|
3961
|
-
trans.
|
|
3962
|
-
roman.
|
|
4121
|
+
trans.textContent = this.lyricLine.translatedLyric;
|
|
4122
|
+
roman.textContent = this.lyricLine.romanLyric;
|
|
3963
4123
|
}
|
|
3964
4124
|
getRubyCharCount(word) {
|
|
3965
4125
|
return (word.ruby ?? []).reduce((total, ruby) => total + ruby.word.length, 0);
|
|
@@ -3977,7 +4137,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3977
4137
|
const rubySegments = this.getRubySegments(word);
|
|
3978
4138
|
for (const ruby of rubySegments) {
|
|
3979
4139
|
const rubyPartEl = document.createElement("span");
|
|
3980
|
-
rubyPartEl.
|
|
4140
|
+
rubyPartEl.textContent = ruby.word;
|
|
3981
4141
|
rubyPartEl.dataset.startTime = String(ruby.startTime);
|
|
3982
4142
|
rubyPartEl.dataset.endTime = String(ruby.endTime);
|
|
3983
4143
|
rubyWordEl.appendChild(rubyPartEl);
|
|
@@ -3994,24 +4154,24 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3994
4154
|
const trimmedWord = displayWord.trim();
|
|
3995
4155
|
if (LyricLineBase.graphemeSegmenter) for (const { segment } of LyricLineBase.graphemeSegmenter.segment(trimmedWord)) {
|
|
3996
4156
|
const charEl = document.createElement("span");
|
|
3997
|
-
charEl.
|
|
4157
|
+
charEl.textContent = segment;
|
|
3998
4158
|
subElements.push(charEl);
|
|
3999
4159
|
wordContainer.appendChild(charEl);
|
|
4000
4160
|
}
|
|
4001
4161
|
else for (const segment of Array.from(trimmedWord)) {
|
|
4002
4162
|
const charEl = document.createElement("span");
|
|
4003
|
-
charEl.
|
|
4163
|
+
charEl.textContent = segment;
|
|
4004
4164
|
subElements.push(charEl);
|
|
4005
4165
|
wordContainer.appendChild(charEl);
|
|
4006
4166
|
}
|
|
4007
4167
|
} else if (hasRomanLine) {
|
|
4008
4168
|
const wordEl = document.createElement("div");
|
|
4009
|
-
wordEl.
|
|
4169
|
+
wordEl.textContent = displayWord.trim();
|
|
4010
4170
|
wordContainer.appendChild(wordEl);
|
|
4011
|
-
} else if (romanWord.length === 0) wordContainer.
|
|
4171
|
+
} else if (romanWord.length === 0) wordContainer.textContent = displayWord.trim();
|
|
4012
4172
|
if (hasRomanLine) {
|
|
4013
4173
|
const romanWordEl = document.createElement("div");
|
|
4014
|
-
romanWordEl.
|
|
4174
|
+
romanWordEl.textContent = romanWord.length > 0 ? romanWord : "\xA0";
|
|
4015
4175
|
romanWordEl.classList.add(lyric_player_module_default.romanWord);
|
|
4016
4176
|
wordContainer.appendChild(romanWordEl);
|
|
4017
4177
|
}
|
|
@@ -4125,7 +4285,7 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4125
4285
|
const glow = el.animate(frames, {
|
|
4126
4286
|
duration: animateDu,
|
|
4127
4287
|
delay: Number.isFinite(wordDe) ? wordDe : 0,
|
|
4128
|
-
id: `emphasize-word-${el.
|
|
4288
|
+
id: `emphasize-word-${el.textContent}-${i}`,
|
|
4129
4289
|
iterations: 1,
|
|
4130
4290
|
composite: "replace",
|
|
4131
4291
|
fill: "both"
|
|
@@ -4375,25 +4535,19 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4375
4535
|
this.element.style.setProperty("--bright-mask-alpha", this.currentBrightAlpha.toFixed(3));
|
|
4376
4536
|
this.element.style.setProperty("--dark-mask-alpha", this.currentDarkAlpha.toFixed(3));
|
|
4377
4537
|
}
|
|
4378
|
-
setTransform(
|
|
4379
|
-
super.setTransform(
|
|
4538
|
+
setTransform(scale = this.scale, opacity = 1, blur = 0, force = false, delay = 0, mode = LyricLineRenderMode.SOLID) {
|
|
4539
|
+
super.setTransform(scale, opacity, blur, force, delay);
|
|
4380
4540
|
this.renderMode = mode;
|
|
4381
|
-
const beforeInSight = this.isInSight;
|
|
4382
4541
|
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
4383
|
-
this.top =
|
|
4542
|
+
this.top = 0;
|
|
4384
4543
|
this.scale = scale;
|
|
4385
4544
|
this.delay = delay * 1e3 | 0;
|
|
4386
4545
|
const main = this.element.children[0];
|
|
4387
4546
|
main.style.opacity = `${opacity}`;
|
|
4388
4547
|
if (force || !enableSpring) {
|
|
4389
4548
|
this.blur = Math.min(32, blur);
|
|
4390
|
-
this.lineTransforms.posY.setPosition(top);
|
|
4391
4549
|
this.lineTransforms.scale.setPosition(scale);
|
|
4392
|
-
|
|
4393
|
-
const afterInSight = this.isInSight;
|
|
4394
|
-
if (beforeInSight || afterInSight) this.show();
|
|
4395
|
-
else this.hide();
|
|
4396
|
-
} else this.rebuildStyle();
|
|
4550
|
+
this.rebuildStyle();
|
|
4397
4551
|
const currentScale = this.lineTransforms.scale.getCurrentPosition();
|
|
4398
4552
|
this.updateMaskAlphaTargets(currentScale / 100);
|
|
4399
4553
|
this.currentBrightAlpha = this.targetBrightAlpha;
|
|
@@ -4401,35 +4555,31 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4401
4555
|
this.element.style.setProperty("--bright-mask-alpha", String(this.currentBrightAlpha));
|
|
4402
4556
|
this.element.style.setProperty("--dark-mask-alpha", String(this.currentDarkAlpha));
|
|
4403
4557
|
} else {
|
|
4404
|
-
this.lineTransforms.posY.setTargetPosition(top, delay);
|
|
4405
4558
|
this.lineTransforms.scale.setTargetPosition(scale);
|
|
4406
4559
|
if (this.blur !== Math.min(5, blur)) {
|
|
4407
4560
|
this.blur = Math.min(5, blur);
|
|
4408
|
-
|
|
4409
|
-
this.element.style.filter = `blur(${roundedBlur}px)`;
|
|
4561
|
+
this.element.style.filter = `blur(${blur.toFixed(3)}px)`;
|
|
4410
4562
|
}
|
|
4411
4563
|
}
|
|
4412
4564
|
}
|
|
4413
4565
|
update(delta = 0) {
|
|
4414
4566
|
if (!this.lyricPlayer.getEnableSpring()) return;
|
|
4415
|
-
this.lineTransforms.posY.update(delta);
|
|
4416
4567
|
this.lineTransforms.scale.update(delta);
|
|
4417
|
-
|
|
4418
|
-
|
|
4568
|
+
this.rebuildStyle();
|
|
4569
|
+
if (!this.built) return;
|
|
4419
4570
|
const currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;
|
|
4420
4571
|
this.updateMaskAlphaTargets(currentScale);
|
|
4421
4572
|
this.applyAlphaToDom(delta);
|
|
4422
4573
|
}
|
|
4574
|
+
/** @internal */
|
|
4423
4575
|
_getDebugTargetPos() {
|
|
4424
4576
|
return `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;
|
|
4425
4577
|
}
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
const ov = this.lyricPlayer.getOverscanPx();
|
|
4432
|
-
return !(t > pb + h + ov || b < -h - ov);
|
|
4578
|
+
teardownContent() {
|
|
4579
|
+
if (this.built) {
|
|
4580
|
+
this.disposeElements();
|
|
4581
|
+
this.built = false;
|
|
4582
|
+
}
|
|
4433
4583
|
}
|
|
4434
4584
|
disposeElements() {
|
|
4435
4585
|
this.balancer?.reset();
|
|
@@ -4462,13 +4612,29 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4462
4612
|
//#endregion
|
|
4463
4613
|
//#region src/lyric-player/dom/index.ts
|
|
4464
4614
|
/**
|
|
4465
|
-
*
|
|
4615
|
+
* 歌词行鼠标相关事件,可以获取到歌词行的索引、主歌词行以及背景歌词行(如果有)元素
|
|
4466
4616
|
*/
|
|
4467
4617
|
var LyricLineMouseEvent = class extends MouseEvent {
|
|
4468
|
-
|
|
4618
|
+
lineIndex;
|
|
4619
|
+
line;
|
|
4620
|
+
bgLine;
|
|
4621
|
+
/**
|
|
4622
|
+
* 自定义标志位,用于记录外部是否调用了 `stopPropagation`
|
|
4623
|
+
*/
|
|
4624
|
+
isPropagationStopped = false;
|
|
4625
|
+
constructor(lineIndex, line, bgLine, event) {
|
|
4469
4626
|
super(`line-${event.type}`, event);
|
|
4470
4627
|
this.lineIndex = lineIndex;
|
|
4471
4628
|
this.line = line;
|
|
4629
|
+
this.bgLine = bgLine;
|
|
4630
|
+
}
|
|
4631
|
+
stopPropagation() {
|
|
4632
|
+
this.isPropagationStopped = true;
|
|
4633
|
+
super.stopPropagation();
|
|
4634
|
+
}
|
|
4635
|
+
stopImmediatePropagation() {
|
|
4636
|
+
this.isPropagationStopped = true;
|
|
4637
|
+
super.stopImmediatePropagation();
|
|
4472
4638
|
}
|
|
4473
4639
|
};
|
|
4474
4640
|
/**
|
|
@@ -4477,7 +4643,8 @@ var LyricLineMouseEvent = class extends MouseEvent {
|
|
|
4477
4643
|
* 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
|
|
4478
4644
|
*/
|
|
4479
4645
|
var DomLyricPlayer = class extends LyricPlayerBase {
|
|
4480
|
-
|
|
4646
|
+
abortController = new AbortController();
|
|
4647
|
+
currentLyricGroups = [];
|
|
4481
4648
|
onResize() {
|
|
4482
4649
|
const computedStyles = getComputedStyle(this.element);
|
|
4483
4650
|
this._baseFontSize = Number.parseFloat(computedStyles.fontSize);
|
|
@@ -4486,10 +4653,18 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4486
4653
|
supportPlusLighter = CSS.supports("mix-blend-mode", "plus-lighter");
|
|
4487
4654
|
supportMaskImage = CSS.supports("mask-image", "none");
|
|
4488
4655
|
innerSize = [0, 0];
|
|
4489
|
-
|
|
4490
|
-
const
|
|
4491
|
-
if (!
|
|
4492
|
-
|
|
4656
|
+
onMouseEventHandler = (e) => {
|
|
4657
|
+
const target = e.target;
|
|
4658
|
+
if (!(target instanceof Element)) return;
|
|
4659
|
+
const groupEl = target.closest(`.${lyric_player_module_default.lyricLineWrapper}`);
|
|
4660
|
+
if (!groupEl) return;
|
|
4661
|
+
const group = this.lyricGroupElementMap.get(groupEl);
|
|
4662
|
+
if (!group) return;
|
|
4663
|
+
const mainLine = group.mainLine;
|
|
4664
|
+
const bgLine = group.bgLine;
|
|
4665
|
+
const evt = new LyricLineMouseEvent(this.lyricLinesIndexes.get(mainLine) ?? -1, mainLine, bgLine, e);
|
|
4666
|
+
if (!this.dispatchEvent(evt) || evt.defaultPrevented) e.preventDefault();
|
|
4667
|
+
if (evt.isPropagationStopped) {
|
|
4493
4668
|
e.stopPropagation();
|
|
4494
4669
|
e.stopImmediatePropagation();
|
|
4495
4670
|
}
|
|
@@ -4510,11 +4685,16 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4510
4685
|
this.onResize();
|
|
4511
4686
|
this.element.classList.add("amll-lyric-player", "dom");
|
|
4512
4687
|
if (this.disableSpring) this.element.classList.add(lyric_player_module_default.disableSpring);
|
|
4688
|
+
this.element.addEventListener("click", this.onMouseEventHandler, { signal: this.abortController.signal });
|
|
4689
|
+
this.element.addEventListener("contextmenu", this.onMouseEventHandler, { signal: this.abortController.signal });
|
|
4513
4690
|
}
|
|
4514
4691
|
rebuildStyle() {}
|
|
4515
4692
|
setWordFadeWidth(value = .5) {
|
|
4516
4693
|
super.setWordFadeWidth(value);
|
|
4517
|
-
for (const
|
|
4694
|
+
for (const group of this.currentLyricGroups) {
|
|
4695
|
+
group.mainLine.updateMaskImageSync();
|
|
4696
|
+
group.bgLine?.updateMaskImageSync();
|
|
4697
|
+
}
|
|
4518
4698
|
}
|
|
4519
4699
|
/**
|
|
4520
4700
|
* 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误
|
|
@@ -4526,36 +4706,43 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4526
4706
|
if (this.hasDuetLine) this.element.classList.add(lyric_player_module_default.hasDuetLine);
|
|
4527
4707
|
else this.element.classList.remove(lyric_player_module_default.hasDuetLine);
|
|
4528
4708
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${initialTime}`);
|
|
4529
|
-
for (const
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
this.currentLyricLineObjects = this.processedLines.map((line, i) => {
|
|
4709
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4710
|
+
this.currentLyricGroups = [];
|
|
4711
|
+
let currentGroup = null;
|
|
4712
|
+
for (let i = 0; i < this.processedLines.length; i++) {
|
|
4713
|
+
const line = this.processedLines[i];
|
|
4535
4714
|
const lineEl = new LyricLineEl(this, line);
|
|
4536
|
-
lineEl.addMouseEventListener("click", this.onLineClickedHandler);
|
|
4537
|
-
lineEl.addMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4538
4715
|
this.lyricLinesIndexes.set(lineEl, i);
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4716
|
+
if (!line.isBG || !currentGroup) {
|
|
4717
|
+
currentGroup = new LyricLineGroup(this, lineEl);
|
|
4718
|
+
this.currentLyricGroups.push(currentGroup);
|
|
4719
|
+
this.lyricGroupElementMap.set(currentGroup.element, currentGroup);
|
|
4720
|
+
} else currentGroup.addBgLine(lineEl);
|
|
4721
|
+
}
|
|
4542
4722
|
this.setLinePosXSpringParams({});
|
|
4543
4723
|
this.setLinePosYSpringParams({});
|
|
4544
4724
|
this.setLineScaleSpringParams({});
|
|
4725
|
+
this.setCurrentTime(initialTime, true);
|
|
4545
4726
|
this.calcLayout(true);
|
|
4546
4727
|
this.update(0);
|
|
4547
4728
|
}
|
|
4548
4729
|
pause() {
|
|
4549
4730
|
super.pause();
|
|
4550
|
-
this.element.classList.remove(
|
|
4731
|
+
this.element.classList.remove(lyric_player_module_default.playing);
|
|
4551
4732
|
this.interludeDots.pause();
|
|
4552
|
-
for (const
|
|
4733
|
+
for (const group of this.currentLyricGroups) {
|
|
4734
|
+
group.mainLine.pause();
|
|
4735
|
+
group.bgLine?.pause();
|
|
4736
|
+
}
|
|
4553
4737
|
}
|
|
4554
4738
|
resume() {
|
|
4555
4739
|
super.resume();
|
|
4556
|
-
this.element.classList.add(
|
|
4740
|
+
this.element.classList.add(lyric_player_module_default.playing);
|
|
4557
4741
|
this.interludeDots.resume();
|
|
4558
|
-
for (const
|
|
4742
|
+
for (const group of this.currentLyricGroups) {
|
|
4743
|
+
group.mainLine.resume();
|
|
4744
|
+
group.bgLine?.resume();
|
|
4745
|
+
}
|
|
4559
4746
|
}
|
|
4560
4747
|
update(delta = 0) {
|
|
4561
4748
|
if (!this.timelineState.initialLayoutFinished) return;
|
|
@@ -4563,12 +4750,13 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4563
4750
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${this.timelineState.currentTime}`);
|
|
4564
4751
|
if (!this.isPageVisible) return;
|
|
4565
4752
|
const deltaS = delta / 1e3;
|
|
4566
|
-
for (const
|
|
4753
|
+
for (const group of this.currentLyricGroups) group.update(deltaS);
|
|
4567
4754
|
}
|
|
4568
4755
|
dispose() {
|
|
4569
4756
|
super.dispose();
|
|
4757
|
+
this.abortController.abort();
|
|
4570
4758
|
this.element.remove();
|
|
4571
|
-
for (const
|
|
4759
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4572
4760
|
this.bottomLine.dispose();
|
|
4573
4761
|
this.interludeDots.dispose();
|
|
4574
4762
|
}
|