@applemusic-like-lyrics/core 0.5.0 → 0.5.1
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 +398 -214
- package/dist/amll-core.cjs.map +1 -1
- package/dist/amll-core.d.cts +125 -67
- package/dist/amll-core.d.mts +125 -67
- package/dist/amll-core.mjs +398 -214
- package/dist/amll-core.mjs.map +1 -1
- package/dist/style.css +129 -63
- package/package.json +2 -2
package/dist/amll-core.cjs
CHANGED
|
@@ -1731,6 +1731,10 @@ var BackgroundRender = class BackgroundRender {
|
|
|
1731
1731
|
//#region src/styles/lyric-player.module.css
|
|
1732
1732
|
var lyric_player_module_default = {
|
|
1733
1733
|
"active": "FmKaba_active",
|
|
1734
|
+
"bgWrapper": "FmKaba_bgWrapper",
|
|
1735
|
+
"bgWrapperActive": "FmKaba_bgWrapperActive",
|
|
1736
|
+
"bgWrapperHidden": "FmKaba_bgWrapperHidden",
|
|
1737
|
+
"bgWrapperTop": "FmKaba_bgWrapperTop",
|
|
1734
1738
|
"bottomLine": "FmKaba_bottomLine",
|
|
1735
1739
|
"dirty": "FmKaba_dirty",
|
|
1736
1740
|
"disableSpring": "FmKaba_disableSpring",
|
|
@@ -1743,8 +1747,10 @@ var lyric_player_module_default = {
|
|
|
1743
1747
|
"lyricBgLine": "FmKaba_lyricBgLine",
|
|
1744
1748
|
"lyricDuetLine": "FmKaba_lyricDuetLine",
|
|
1745
1749
|
"lyricLine": "FmKaba_lyricLine",
|
|
1750
|
+
"lyricLineWrapper": "FmKaba_lyricLineWrapper",
|
|
1746
1751
|
"lyricMainLine": "FmKaba_lyricMainLine",
|
|
1747
1752
|
"lyricSubLine": "FmKaba_lyricSubLine",
|
|
1753
|
+
"playing": "FmKaba_playing",
|
|
1748
1754
|
"romanWord": "FmKaba_romanWord",
|
|
1749
1755
|
"rubyWord": "FmKaba_rubyWord",
|
|
1750
1756
|
"tmpDisableTransition": "FmKaba_tmpDisableTransition",
|
|
@@ -1845,27 +1851,31 @@ function cleanUnintentionalOverlaps(lines) {
|
|
|
1845
1851
|
* 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试最多提前 400ms 或上一行时长的 30%
|
|
1846
1852
|
*/
|
|
1847
1853
|
function tryAdvanceStartTime(lines) {
|
|
1848
|
-
|
|
1854
|
+
const defaultAdvanceAmount = 600;
|
|
1855
|
+
const fallbackAdvanceAmount = 400;
|
|
1856
|
+
const fallbackAdvanceRatio = .3;
|
|
1857
|
+
let prevLineStartTime = 0;
|
|
1858
|
+
let prevLineEndTime = 0;
|
|
1859
|
+
let prevMainGroupStartTime = 0;
|
|
1860
|
+
let prevMainGroupEndTime = 0;
|
|
1861
|
+
let hasPrevLine = false;
|
|
1862
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1849
1863
|
const line = lines[i];
|
|
1850
1864
|
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
|
-
}
|
|
1865
|
+
const originalStartTime = line.startTime;
|
|
1866
|
+
const originalEndTime = line.endTime;
|
|
1857
1867
|
let targetAdvanceAmount = 0;
|
|
1858
1868
|
let safeBoundary = 0;
|
|
1859
|
-
if (
|
|
1860
|
-
targetAdvanceAmount =
|
|
1861
|
-
safeBoundary =
|
|
1869
|
+
if (hasPrevLine) if (originalStartTime >= prevLineEndTime) {
|
|
1870
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1871
|
+
safeBoundary = prevMainGroupEndTime;
|
|
1862
1872
|
} else {
|
|
1863
|
-
targetAdvanceAmount =
|
|
1864
|
-
const prevDuration =
|
|
1865
|
-
safeBoundary =
|
|
1873
|
+
targetAdvanceAmount = fallbackAdvanceAmount;
|
|
1874
|
+
const prevDuration = prevLineEndTime - prevLineStartTime;
|
|
1875
|
+
safeBoundary = prevLineStartTime + prevDuration * fallbackAdvanceRatio;
|
|
1866
1876
|
}
|
|
1867
1877
|
else {
|
|
1868
|
-
targetAdvanceAmount =
|
|
1878
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1869
1879
|
safeBoundary = 0;
|
|
1870
1880
|
}
|
|
1871
1881
|
const targetTime = line.startTime - targetAdvanceAmount;
|
|
@@ -1873,6 +1883,20 @@ function tryAdvanceStartTime(lines) {
|
|
|
1873
1883
|
if (newStartTime < line.startTime) line.startTime = newStartTime;
|
|
1874
1884
|
const nextLine = lines[i + 1];
|
|
1875
1885
|
if (nextLine?.isBG) nextLine.startTime = line.startTime;
|
|
1886
|
+
if (hasPrevLine) if (originalStartTime < prevMainGroupEndTime && originalEndTime > prevMainGroupStartTime) {
|
|
1887
|
+
prevMainGroupStartTime = Math.min(prevMainGroupStartTime, originalStartTime);
|
|
1888
|
+
prevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);
|
|
1889
|
+
} else {
|
|
1890
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1891
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1892
|
+
}
|
|
1893
|
+
else {
|
|
1894
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1895
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1896
|
+
}
|
|
1897
|
+
prevLineStartTime = originalStartTime;
|
|
1898
|
+
prevLineEndTime = originalEndTime;
|
|
1899
|
+
hasPrevLine = true;
|
|
1876
1900
|
}
|
|
1877
1901
|
}
|
|
1878
1902
|
/**
|
|
@@ -2272,19 +2296,19 @@ const LayoutAlignAnchor = {
|
|
|
2272
2296
|
function computeCurrentInterlude(input) {
|
|
2273
2297
|
const currentTime = input.currentTime + 20;
|
|
2274
2298
|
const currentIndex = input.scrollToIndex;
|
|
2275
|
-
const
|
|
2299
|
+
const groups = input.currentGroups;
|
|
2276
2300
|
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;
|
|
2301
|
+
if (k < -1 || k >= groups.length - 1) return void 0;
|
|
2302
|
+
const prevGroup = k === -1 ? null : groups[k];
|
|
2303
|
+
const nextGroup = groups[k + 1];
|
|
2304
|
+
const gapStart = prevGroup ? prevGroup.endTime : 0;
|
|
2305
|
+
const gapEnd = Math.max(gapStart, nextGroup.startTime - 250);
|
|
2306
|
+
if (gapEnd - gapStart < 4e3) return void 0;
|
|
2283
2307
|
if (gapEnd > currentTime && gapStart < currentTime) return {
|
|
2284
2308
|
startTime: Math.max(gapStart, currentTime),
|
|
2285
2309
|
endTime: gapEnd,
|
|
2286
2310
|
anchorLineIndex: k,
|
|
2287
|
-
isNextDuet:
|
|
2311
|
+
isNextDuet: nextGroup.mainLine.getLine().isDuet
|
|
2288
2312
|
};
|
|
2289
2313
|
};
|
|
2290
2314
|
return checkGap(currentIndex - 1) || checkGap(currentIndex) || checkGap(currentIndex + 1);
|
|
@@ -2297,8 +2321,8 @@ function computeCurrentInterlude(input) {
|
|
|
2297
2321
|
* - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping
|
|
2298
2322
|
*/
|
|
2299
2323
|
function computeLinePosYSpringParams(input) {
|
|
2300
|
-
const { enabled,
|
|
2301
|
-
if (!enabled ||
|
|
2324
|
+
const { enabled, currentGroups, scrollToIndex, isSeeking, isInterludeActive } = input;
|
|
2325
|
+
if (!enabled || currentGroups.length === 0) return { shouldUpdate: false };
|
|
2302
2326
|
if (isSeeking || isInterludeActive) return {
|
|
2303
2327
|
shouldUpdate: true,
|
|
2304
2328
|
params: {
|
|
@@ -2306,10 +2330,10 @@ function computeLinePosYSpringParams(input) {
|
|
|
2306
2330
|
damping: 15
|
|
2307
2331
|
}
|
|
2308
2332
|
};
|
|
2309
|
-
const
|
|
2310
|
-
const
|
|
2311
|
-
if (!
|
|
2312
|
-
const interval =
|
|
2333
|
+
const currentGroup = currentGroups[scrollToIndex];
|
|
2334
|
+
const prevGroup = currentGroups[scrollToIndex - 1];
|
|
2335
|
+
if (!currentGroup || !prevGroup) return { shouldUpdate: false };
|
|
2336
|
+
const interval = currentGroup.startTime - prevGroup.startTime;
|
|
2313
2337
|
const MIN_INTERVAL = 100;
|
|
2314
2338
|
const MAX_INTERVAL = 800;
|
|
2315
2339
|
const clampedInterval = clamp(interval, MIN_INTERVAL, MAX_INTERVAL);
|
|
@@ -2327,38 +2351,33 @@ function computeLinePosYSpringParams(input) {
|
|
|
2327
2351
|
};
|
|
2328
2352
|
}
|
|
2329
2353
|
/**
|
|
2330
|
-
*
|
|
2354
|
+
* 计算一组歌词在当前布局中的视觉呈现参数。
|
|
2331
2355
|
*
|
|
2332
2356
|
* 根据播放状态、缓冲状态、布局模式与间奏信息,
|
|
2333
|
-
*
|
|
2357
|
+
* 生成一组歌词最终应使用的活跃状态、不透明度与模糊值。
|
|
2334
2358
|
*/
|
|
2335
|
-
function
|
|
2336
|
-
const {
|
|
2337
|
-
const isActive = hasBuffered ||
|
|
2359
|
+
function computeGroupPresentation(input) {
|
|
2360
|
+
const { groupIndex, scrollToIndex, latestIndex, hasBuffered, hidePassedLines, isPlaying, isNonDynamic, enableBlur, isUserScrolling, isCompact, interlude } = input;
|
|
2361
|
+
const isActive = hasBuffered || groupIndex >= scrollToIndex && groupIndex < latestIndex;
|
|
2338
2362
|
const blurLevel = computeLineBlur({
|
|
2339
2363
|
enableBlur,
|
|
2340
2364
|
isUserScrolling,
|
|
2341
2365
|
isActive,
|
|
2342
|
-
itemIndex:
|
|
2366
|
+
itemIndex: groupIndex,
|
|
2343
2367
|
scrollToIndex,
|
|
2344
2368
|
latestIndex,
|
|
2345
2369
|
isCompact
|
|
2346
2370
|
});
|
|
2347
2371
|
let targetOpacity;
|
|
2348
|
-
if (hidePassedLines) if (
|
|
2372
|
+
if (hidePassedLines) if (groupIndex < (interlude ? interlude.anchorLineIndex + 1 : scrollToIndex) && isPlaying) targetOpacity = 1e-4;
|
|
2349
2373
|
else if (hasBuffered) targetOpacity = .85;
|
|
2350
2374
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2351
2375
|
else if (hasBuffered) targetOpacity = .85;
|
|
2352
2376
|
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
2377
|
return {
|
|
2357
2378
|
isActive,
|
|
2358
2379
|
targetOpacity,
|
|
2359
|
-
|
|
2360
|
-
blurLevel,
|
|
2361
|
-
renderMode: isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID
|
|
2380
|
+
blurLevel
|
|
2362
2381
|
};
|
|
2363
2382
|
}
|
|
2364
2383
|
/**
|
|
@@ -2514,50 +2533,29 @@ const eqSet = (xs, ys) => xs.size === ys.size && [...xs].every((x) => ys.has(x))
|
|
|
2514
2533
|
* - 根据新的热行状态和已有的缓冲行状态,计算出应移除的缓冲行 ID
|
|
2515
2534
|
*/
|
|
2516
2535
|
function computePlayerTimeState(input) {
|
|
2517
|
-
const { time,
|
|
2518
|
-
const
|
|
2536
|
+
const { time, currentGroups, timelineState: { hotGroups, bufferedGroups } } = input;
|
|
2537
|
+
const nextHotGroups = new Set(hotGroups);
|
|
2519
2538
|
const addedIds = /* @__PURE__ */ new Set();
|
|
2520
2539
|
const removedHotIds = /* @__PURE__ */ new Set();
|
|
2521
2540
|
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);
|
|
2541
|
+
for (const lastHotId of hotGroups) {
|
|
2542
|
+
const group = currentGroups[lastHotId];
|
|
2543
|
+
if (!group || time < group.startTime || group.endTime <= time) {
|
|
2544
|
+
nextHotGroups.delete(lastHotId);
|
|
2543
2545
|
removedHotIds.add(lastHotId);
|
|
2544
2546
|
}
|
|
2545
2547
|
}
|
|
2546
|
-
for (let id = 0; id <
|
|
2547
|
-
const
|
|
2548
|
-
if (!
|
|
2549
|
-
if (
|
|
2550
|
-
|
|
2548
|
+
for (let id = 0; id < currentGroups.length; id++) {
|
|
2549
|
+
const group = currentGroups[id];
|
|
2550
|
+
if (!group) continue;
|
|
2551
|
+
if (group.startTime <= time && group.endTime > time && !nextHotGroups.has(id)) {
|
|
2552
|
+
nextHotGroups.add(id);
|
|
2551
2553
|
addedIds.add(id);
|
|
2552
|
-
if (processedLines[id + 1]?.isBG) {
|
|
2553
|
-
nextHotLines.add(id + 1);
|
|
2554
|
-
addedIds.add(id + 1);
|
|
2555
|
-
}
|
|
2556
2554
|
}
|
|
2557
2555
|
}
|
|
2558
|
-
for (const id of
|
|
2556
|
+
for (const id of bufferedGroups) if (!nextHotGroups.has(id)) removedBufferedIds.add(id);
|
|
2559
2557
|
return {
|
|
2560
|
-
|
|
2558
|
+
nextHotGroups,
|
|
2561
2559
|
addedIds,
|
|
2562
2560
|
removedHotIds,
|
|
2563
2561
|
removedBufferedIds
|
|
@@ -2569,10 +2567,10 @@ function computePlayerTimeState(input) {
|
|
|
2569
2567
|
* 若当前仍存在缓冲行,则优先对齐到最靠前的缓冲行;
|
|
2570
2568
|
* 否则对齐到第一条开始时间不小于当前时间的歌词行。
|
|
2571
2569
|
*/
|
|
2572
|
-
function pickScrollToIndexForSeek(time,
|
|
2573
|
-
if (
|
|
2574
|
-
const foundIndex =
|
|
2575
|
-
return foundIndex === -1 ?
|
|
2570
|
+
function pickScrollToIndexForSeek(time, currentGroups, bufferedGroups) {
|
|
2571
|
+
if (bufferedGroups.size > 0) return Math.min(...bufferedGroups);
|
|
2572
|
+
const foundIndex = currentGroups.findIndex((group) => group.startTime >= time);
|
|
2573
|
+
return foundIndex === -1 ? currentGroups.length : foundIndex;
|
|
2576
2574
|
}
|
|
2577
2575
|
/**
|
|
2578
2576
|
* 提交时间线状态转移的纯函数。
|
|
@@ -2582,45 +2580,45 @@ function pickScrollToIndexForSeek(time, processedLines, bufferedLines) {
|
|
|
2582
2580
|
* 是否需要重置用户滚动状态、是否需要触发布局。
|
|
2583
2581
|
*/
|
|
2584
2582
|
function commitPlayerTimeState(input) {
|
|
2585
|
-
const { timelineState, time,
|
|
2583
|
+
const { timelineState, time, currentGroups, hasBottomContent, stateResult } = input;
|
|
2586
2584
|
const { addedIds, removedHotIds, removedBufferedIds } = stateResult;
|
|
2587
2585
|
const { isSeeking } = timelineState;
|
|
2588
2586
|
timelineState.currentTime = time;
|
|
2589
|
-
timelineState.
|
|
2587
|
+
timelineState.hotGroups = stateResult.nextHotGroups;
|
|
2590
2588
|
let shouldLayout = false;
|
|
2591
2589
|
let shouldResetScroll = false;
|
|
2592
|
-
const
|
|
2593
|
-
const
|
|
2590
|
+
const groupsToEnable = [];
|
|
2591
|
+
const groupsToDisable = /* @__PURE__ */ new Set();
|
|
2594
2592
|
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)
|
|
2593
|
+
timelineState.bufferedGroups = new Set([...timelineState.hotGroups]);
|
|
2594
|
+
timelineState.scrollToIndex = pickScrollToIndexForSeek(time, currentGroups, timelineState.bufferedGroups);
|
|
2595
|
+
for (const id of removedHotIds) groupsToDisable.add(id);
|
|
2596
|
+
for (const id of timelineState.hotGroups) groupsToEnable.push(id);
|
|
2597
|
+
for (const id of removedBufferedIds) groupsToDisable.add(id);
|
|
2600
2598
|
shouldResetScroll = true;
|
|
2601
2599
|
shouldLayout = true;
|
|
2602
2600
|
} else if (addedIds.size > 0) {
|
|
2603
2601
|
for (const id of addedIds) {
|
|
2604
|
-
timelineState.
|
|
2605
|
-
|
|
2602
|
+
timelineState.bufferedGroups.add(id);
|
|
2603
|
+
groupsToEnable.push(id);
|
|
2606
2604
|
}
|
|
2607
2605
|
for (const id of removedBufferedIds) {
|
|
2608
|
-
timelineState.
|
|
2609
|
-
|
|
2606
|
+
timelineState.bufferedGroups.delete(id);
|
|
2607
|
+
groupsToDisable.add(id);
|
|
2610
2608
|
}
|
|
2611
|
-
if (timelineState.
|
|
2609
|
+
if (timelineState.bufferedGroups.size > 0) timelineState.scrollToIndex = Math.min(...timelineState.bufferedGroups);
|
|
2612
2610
|
shouldLayout = true;
|
|
2613
|
-
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.
|
|
2614
|
-
for (const id of timelineState.
|
|
2615
|
-
if (timelineState.
|
|
2616
|
-
timelineState.
|
|
2617
|
-
|
|
2611
|
+
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.bufferedGroups)) {
|
|
2612
|
+
for (const id of timelineState.bufferedGroups) {
|
|
2613
|
+
if (timelineState.hotGroups.has(id)) continue;
|
|
2614
|
+
timelineState.bufferedGroups.delete(id);
|
|
2615
|
+
groupsToDisable.add(id);
|
|
2618
2616
|
}
|
|
2619
2617
|
shouldLayout = true;
|
|
2620
2618
|
}
|
|
2621
|
-
if (timelineState.
|
|
2622
|
-
if (time >=
|
|
2623
|
-
const targetIndex = hasBottomContent ?
|
|
2619
|
+
if (timelineState.bufferedGroups.size === 0 && currentGroups.length > 0) {
|
|
2620
|
+
if (time >= currentGroups[currentGroups.length - 1].endTime) {
|
|
2621
|
+
const targetIndex = hasBottomContent ? currentGroups.length : currentGroups.length - 1;
|
|
2624
2622
|
if (timelineState.scrollToIndex !== targetIndex) {
|
|
2625
2623
|
timelineState.scrollToIndex = targetIndex;
|
|
2626
2624
|
shouldLayout = true;
|
|
@@ -2631,8 +2629,8 @@ function commitPlayerTimeState(input) {
|
|
|
2631
2629
|
return {
|
|
2632
2630
|
shouldLayout,
|
|
2633
2631
|
shouldResetScroll,
|
|
2634
|
-
|
|
2635
|
-
|
|
2632
|
+
groupsToEnable,
|
|
2633
|
+
groupsToDisable: [...groupsToDisable]
|
|
2636
2634
|
};
|
|
2637
2635
|
}
|
|
2638
2636
|
//#endregion
|
|
@@ -2647,17 +2645,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2647
2645
|
timelineState = {
|
|
2648
2646
|
currentTime: 0,
|
|
2649
2647
|
lastCurrentTime: 0,
|
|
2650
|
-
|
|
2651
|
-
|
|
2648
|
+
hotGroups: /* @__PURE__ */ new Set(),
|
|
2649
|
+
bufferedGroups: /* @__PURE__ */ new Set(),
|
|
2652
2650
|
scrollToIndex: 0,
|
|
2653
2651
|
isSeeking: false,
|
|
2654
2652
|
isPlaying: true,
|
|
2655
2653
|
initialLayoutFinished: false
|
|
2656
2654
|
};
|
|
2657
2655
|
/** @internal */
|
|
2658
|
-
|
|
2659
|
-
/** @internal */
|
|
2660
|
-
lyricLineElementMap = /* @__PURE__ */ new WeakMap();
|
|
2656
|
+
lyricGroupElementMap = /* @__PURE__ */ new WeakMap();
|
|
2661
2657
|
currentLyricLines = [];
|
|
2662
2658
|
processedLines = [];
|
|
2663
2659
|
lyricLinesIndexes = /* @__PURE__ */ new WeakMap();
|
|
@@ -2689,10 +2685,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2689
2685
|
isScrolled: false,
|
|
2690
2686
|
isUserScrolling: false
|
|
2691
2687
|
};
|
|
2692
|
-
|
|
2688
|
+
currentLyricGroups = [];
|
|
2689
|
+
lyricGroupSize = /* @__PURE__ */ new WeakMap();
|
|
2693
2690
|
size = [0, 0];
|
|
2694
2691
|
isPageVisible = true;
|
|
2695
2692
|
optimizeOptions = {};
|
|
2693
|
+
/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */
|
|
2694
|
+
alwaysPostpositionBackground = false;
|
|
2696
2695
|
posXSpringParams = {
|
|
2697
2696
|
mass: 1,
|
|
2698
2697
|
damping: 10,
|
|
@@ -2742,13 +2741,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2742
2741
|
shouldRelayout = true;
|
|
2743
2742
|
}
|
|
2744
2743
|
} else {
|
|
2745
|
-
const
|
|
2746
|
-
if (
|
|
2744
|
+
const groupObj = this.lyricGroupElementMap.get(entry.target);
|
|
2745
|
+
if (groupObj) {
|
|
2747
2746
|
const newSize = [entry.target.clientWidth, entry.target.clientHeight];
|
|
2748
|
-
const oldSize = this.
|
|
2747
|
+
const oldSize = this.lyricGroupSize.get(groupObj) ?? [0, 0];
|
|
2749
2748
|
if (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {
|
|
2750
|
-
this.
|
|
2751
|
-
|
|
2749
|
+
this.lyricGroupSize.set(groupObj, newSize);
|
|
2750
|
+
groupObj.onLineSizeChange(newSize);
|
|
2752
2751
|
shouldRelayout = true;
|
|
2753
2752
|
}
|
|
2754
2753
|
}
|
|
@@ -2874,7 +2873,7 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2874
2873
|
}
|
|
2875
2874
|
}
|
|
2876
2875
|
rebuildLyricLines() {
|
|
2877
|
-
for (const
|
|
2876
|
+
for (const group of this.currentLyricGroups) group.rebuildAllLines();
|
|
2878
2877
|
}
|
|
2879
2878
|
/**
|
|
2880
2879
|
* 根据当前配置处理不雅用语单词
|
|
@@ -2976,11 +2975,11 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2976
2975
|
break;
|
|
2977
2976
|
}
|
|
2978
2977
|
this.hasDuetLine = this.processedLines.some((line) => line.isDuet);
|
|
2979
|
-
for (const
|
|
2978
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
2979
|
+
this.currentLyricGroups = [];
|
|
2980
2980
|
this.interludeDots.setInterlude(void 0);
|
|
2981
|
-
this.timelineState.
|
|
2982
|
-
this.timelineState.
|
|
2983
|
-
this.setCurrentTime(0, true);
|
|
2981
|
+
this.timelineState.hotGroups.clear();
|
|
2982
|
+
this.timelineState.bufferedGroups.clear();
|
|
2984
2983
|
if (process.env.NODE_ENV !== "production") console.log("歌词处理完成", this);
|
|
2985
2984
|
}
|
|
2986
2985
|
/**
|
|
@@ -3006,19 +3005,19 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3006
3005
|
if (!timelineState.initialLayoutFinished && !timelineState.isSeeking) return;
|
|
3007
3006
|
const stateResult = computePlayerTimeState({
|
|
3008
3007
|
time,
|
|
3009
|
-
|
|
3008
|
+
currentGroups: this.currentLyricGroups,
|
|
3010
3009
|
timelineState
|
|
3011
3010
|
});
|
|
3012
3011
|
const hasBottomContent = this.bottomLine.getElement().innerHTML.trim().length > 0;
|
|
3013
3012
|
const commitResult = commitPlayerTimeState({
|
|
3014
3013
|
timelineState,
|
|
3015
3014
|
time,
|
|
3016
|
-
|
|
3015
|
+
currentGroups: this.currentLyricGroups,
|
|
3017
3016
|
hasBottomContent,
|
|
3018
3017
|
stateResult
|
|
3019
3018
|
});
|
|
3020
|
-
for (const id of commitResult.
|
|
3021
|
-
for (const id of commitResult.
|
|
3019
|
+
for (const id of commitResult.groupsToDisable) this.currentLyricGroups[id]?.disable();
|
|
3020
|
+
for (const id of commitResult.groupsToEnable) this.currentLyricGroups[id]?.enable();
|
|
3022
3021
|
if (commitResult.shouldResetScroll) this.resetScroll();
|
|
3023
3022
|
if (commitResult.shouldLayout) this.calcLayout();
|
|
3024
3023
|
}
|
|
@@ -3043,14 +3042,14 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3043
3042
|
const interlude = computeCurrentInterlude({
|
|
3044
3043
|
currentTime: this.timelineState.currentTime,
|
|
3045
3044
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3046
|
-
|
|
3045
|
+
currentGroups: this.currentLyricGroups
|
|
3047
3046
|
});
|
|
3048
3047
|
const isInterludeActive = !!interlude;
|
|
3049
3048
|
if (this.layoutState.targetAlignIndex !== this.timelineState.scrollToIndex || this.layoutState.lastInterludeState !== isInterludeActive) {
|
|
3050
3049
|
this.layoutState.lastInterludeState = isInterludeActive;
|
|
3051
3050
|
const springParams = computeLinePosYSpringParams({
|
|
3052
3051
|
enabled: this.getEnableSpring(),
|
|
3053
|
-
|
|
3052
|
+
currentGroups: this.currentLyricGroups,
|
|
3054
3053
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3055
3054
|
isSeeking: this.timelineState.isSeeking,
|
|
3056
3055
|
isInterludeActive
|
|
@@ -3068,17 +3067,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3068
3067
|
if (interlude.anchorLineIndex !== -1) curPos -= totalInterludeHeight;
|
|
3069
3068
|
}
|
|
3070
3069
|
const LINE_HEIGHT_FALLBACK = this.size[1] / 5;
|
|
3071
|
-
const scrollOffset = this.
|
|
3070
|
+
const scrollOffset = this.currentLyricGroups.slice(0, targetAlignIndex).reduce((acc, group) => acc + (this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK), 0);
|
|
3072
3071
|
this.scrollState.scrollBoundary.minOffset = -scrollOffset;
|
|
3073
3072
|
curPos -= scrollOffset;
|
|
3074
3073
|
curPos += this.size[1] * this.layoutState.alignPosition;
|
|
3075
|
-
const
|
|
3074
|
+
const curGroup = this.currentLyricGroups[targetAlignIndex];
|
|
3076
3075
|
this.layoutState.targetAlignIndex = targetAlignIndex;
|
|
3077
|
-
const isBottomFocused = targetAlignIndex === this.
|
|
3076
|
+
const isBottomFocused = targetAlignIndex === this.currentLyricGroups.length;
|
|
3078
3077
|
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];
|
|
3078
|
+
const targetLineHeight = curGroup ? this.lyricGroupSize.get(curGroup)?.[1] ?? LINE_HEIGHT_FALLBACK : isBottomFocused ? this.bottomLine.lineSize[1] : 0;
|
|
3082
3079
|
if (targetLineHeight > 0) switch (this.layoutState.alignAnchor) {
|
|
3083
3080
|
case LayoutAlignAnchor.Bottom:
|
|
3084
3081
|
curPos -= targetLineHeight;
|
|
@@ -3088,13 +3085,12 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3088
3085
|
break;
|
|
3089
3086
|
case LayoutAlignAnchor.Top: break;
|
|
3090
3087
|
}
|
|
3091
|
-
const latestIndex = Math.max(...this.timelineState.
|
|
3088
|
+
const latestIndex = Math.max(...this.timelineState.bufferedGroups);
|
|
3092
3089
|
let delay = 0;
|
|
3093
3090
|
let baseDelay = sync ? 0 : .05;
|
|
3094
3091
|
let setDots = false;
|
|
3095
|
-
this.
|
|
3096
|
-
const hasBuffered = this.timelineState.
|
|
3097
|
-
const line = lineObj.getLine();
|
|
3092
|
+
this.currentLyricGroups.forEach((group, i) => {
|
|
3093
|
+
const hasBuffered = this.timelineState.bufferedGroups.has(i);
|
|
3098
3094
|
const shouldShowDots = interlude && i === interlude.anchorLineIndex + 1;
|
|
3099
3095
|
if (!setDots && shouldShowDots) {
|
|
3100
3096
|
setDots = true;
|
|
@@ -3106,31 +3102,28 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3106
3102
|
curPos += this.layoutState.interludeDotsSize[1];
|
|
3107
3103
|
curPos += dotMargin;
|
|
3108
3104
|
}
|
|
3109
|
-
const presentation =
|
|
3110
|
-
|
|
3111
|
-
lineIndex: i,
|
|
3105
|
+
const presentation = computeGroupPresentation({
|
|
3106
|
+
groupIndex: i,
|
|
3112
3107
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3113
3108
|
latestIndex,
|
|
3114
3109
|
hasBuffered,
|
|
3115
3110
|
hidePassedLines: this.hidePassedLines,
|
|
3116
3111
|
isPlaying: this.timelineState.isPlaying,
|
|
3117
3112
|
isNonDynamic: this.isNonDynamic,
|
|
3118
|
-
enableScale: this.enableScale,
|
|
3119
3113
|
enableBlur: this.enableBlur,
|
|
3120
3114
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
3121
3115
|
isCompact: window.innerWidth <= 1024,
|
|
3122
3116
|
interlude
|
|
3123
3117
|
});
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
else if (!line.isBG) curPos += this.lyricLinesSize.get(lineObj)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3118
|
+
group.setTransform(curPos, force, delay, presentation.isActive, presentation.targetOpacity, presentation.blurLevel);
|
|
3119
|
+
curPos += this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3127
3120
|
if (curPos >= 0 && !this.timelineState.isSeeking) {
|
|
3128
|
-
|
|
3121
|
+
delay += baseDelay;
|
|
3129
3122
|
if (i >= this.timelineState.scrollToIndex) baseDelay /= 1.05;
|
|
3130
3123
|
}
|
|
3131
3124
|
});
|
|
3132
3125
|
this.scrollState.scrollBoundary.maxOffset = curPos + this.scrollState.scrollOffset - this.size[1] / 2;
|
|
3133
|
-
const bottomIndex = this.
|
|
3126
|
+
const bottomIndex = this.currentLyricGroups.length;
|
|
3134
3127
|
const finalBottomBlur = computeLineBlur({
|
|
3135
3128
|
enableBlur: this.enableBlur,
|
|
3136
3129
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
@@ -3160,7 +3153,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3160
3153
|
...params
|
|
3161
3154
|
};
|
|
3162
3155
|
this.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);
|
|
3163
|
-
for (const
|
|
3156
|
+
for (const group of this.currentLyricGroups) {
|
|
3157
|
+
group.posY.updateParams(this.posYSpringParams);
|
|
3158
|
+
group.bgSlideY.updateParams(this.posYSpringParams);
|
|
3159
|
+
}
|
|
3164
3160
|
}
|
|
3165
3161
|
/**
|
|
3166
3162
|
* 设置所有歌词行在缩放大小上的弹簧属性,包括重量、弹力和阻力。
|
|
@@ -3176,8 +3172,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3176
3172
|
...this.scaleForBGSpringParams,
|
|
3177
3173
|
...params
|
|
3178
3174
|
};
|
|
3179
|
-
for (const
|
|
3180
|
-
|
|
3175
|
+
for (const group of this.currentLyricGroups) {
|
|
3176
|
+
group.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);
|
|
3177
|
+
group.bgLine?.lineTransforms.scale.updateParams(this.scaleForBGSpringParams);
|
|
3178
|
+
}
|
|
3181
3179
|
}
|
|
3182
3180
|
/**
|
|
3183
3181
|
* 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来
|
|
@@ -3249,6 +3247,23 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3249
3247
|
getCurrentTime() {
|
|
3250
3248
|
return this.timelineState.currentTime;
|
|
3251
3249
|
}
|
|
3250
|
+
/**
|
|
3251
|
+
* 设置是否让背景人声行始终后置显示
|
|
3252
|
+
*
|
|
3253
|
+
* 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;
|
|
3254
|
+
* 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示
|
|
3255
|
+
* @param enable 是否启用始终后置
|
|
3256
|
+
*/
|
|
3257
|
+
setAlwaysPostpositionBackground(enable) {
|
|
3258
|
+
if (this.alwaysPostpositionBackground === enable) return;
|
|
3259
|
+
this.alwaysPostpositionBackground = enable;
|
|
3260
|
+
this.rebuildLyricLines();
|
|
3261
|
+
this.calcLayout();
|
|
3262
|
+
}
|
|
3263
|
+
/** 获取当前是否设置了让背景人声行始终后置显示 */
|
|
3264
|
+
getAlwaysPostpositionBackground() {
|
|
3265
|
+
return this.alwaysPostpositionBackground;
|
|
3266
|
+
}
|
|
3252
3267
|
getElement() {
|
|
3253
3268
|
return this.element;
|
|
3254
3269
|
}
|
|
@@ -3259,6 +3274,191 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3259
3274
|
}
|
|
3260
3275
|
};
|
|
3261
3276
|
//#endregion
|
|
3277
|
+
//#region src/lyric-player/base/group.ts
|
|
3278
|
+
var LyricLineGroupBase = class {
|
|
3279
|
+
posY = new Spring(0);
|
|
3280
|
+
bgSlideY = new Spring(-80);
|
|
3281
|
+
top = 0;
|
|
3282
|
+
delay = 0;
|
|
3283
|
+
isActive = false;
|
|
3284
|
+
opacity = 1;
|
|
3285
|
+
blur = 0;
|
|
3286
|
+
isBgFirst = false;
|
|
3287
|
+
constructor(mainLine, bgLine) {
|
|
3288
|
+
this.mainLine = mainLine;
|
|
3289
|
+
this.bgLine = bgLine;
|
|
3290
|
+
}
|
|
3291
|
+
get startTime() {
|
|
3292
|
+
return this.mainLine.getLine().startTime;
|
|
3293
|
+
}
|
|
3294
|
+
get endTime() {
|
|
3295
|
+
return this.mainLine.getLine().endTime;
|
|
3296
|
+
}
|
|
3297
|
+
onLineSizeChange(size) {
|
|
3298
|
+
this.mainLine.onLineSizeChange(size);
|
|
3299
|
+
this.bgLine?.onLineSizeChange(size);
|
|
3300
|
+
}
|
|
3301
|
+
setTransform(top, force, delay, isActive, opacity, blur) {
|
|
3302
|
+
this.top = top;
|
|
3303
|
+
this.delay = delay;
|
|
3304
|
+
this.isActive = isActive;
|
|
3305
|
+
this.opacity = opacity;
|
|
3306
|
+
this.blur = blur;
|
|
3307
|
+
this.setLineTransformations(force, delay);
|
|
3308
|
+
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
3309
|
+
const hiddenSlideY = (this.lyricPlayer.getAlwaysPostpositionBackground() ? false : this.isBgFirst) ? 80 : -80;
|
|
3310
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3311
|
+
const targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;
|
|
3312
|
+
if (force || !enableSpring) {
|
|
3313
|
+
this.posY.setPosition(top);
|
|
3314
|
+
this.bgSlideY.setPosition(targetBgSlideY);
|
|
3315
|
+
this.renderStyles();
|
|
3316
|
+
} else {
|
|
3317
|
+
this.posY.setTargetPosition(top, delay);
|
|
3318
|
+
this.bgSlideY.setTargetPosition(targetBgSlideY, delay);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
setLineTransformations(force, delay) {
|
|
3322
|
+
const enableScale = this.lyricPlayer.getEnableScale();
|
|
3323
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3324
|
+
const renderMode = this.isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID;
|
|
3325
|
+
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
3326
|
+
let mainScale = 100;
|
|
3327
|
+
if (!this.isActive && isPlaying) mainScale = SCALE_ASPECT;
|
|
3328
|
+
this.mainLine.setTransform(mainScale, 1, 0, force, delay, renderMode);
|
|
3329
|
+
let bgScale = 100;
|
|
3330
|
+
if (!this.isActive && isPlaying) bgScale = 75;
|
|
3331
|
+
this.bgLine?.setTransform(bgScale, 1, 0, force, delay, renderMode);
|
|
3332
|
+
}
|
|
3333
|
+
update(delta) {
|
|
3334
|
+
if (this.lyricPlayer.getEnableSpring()) {
|
|
3335
|
+
this.posY.update(delta);
|
|
3336
|
+
this.bgSlideY.update(delta);
|
|
3337
|
+
this.renderStyles();
|
|
3338
|
+
}
|
|
3339
|
+
this.mainLine.update(delta);
|
|
3340
|
+
this.bgLine?.update(delta);
|
|
3341
|
+
}
|
|
3342
|
+
rebuildAllLines() {
|
|
3343
|
+
this.mainLine.rebuildElement();
|
|
3344
|
+
this.bgLine?.rebuildElement();
|
|
3345
|
+
}
|
|
3346
|
+
enable(time, shouldPlay) {
|
|
3347
|
+
this.mainLine.enable(time, shouldPlay);
|
|
3348
|
+
this.bgLine?.enable(time, shouldPlay);
|
|
3349
|
+
}
|
|
3350
|
+
disable() {
|
|
3351
|
+
this.mainLine.disable();
|
|
3352
|
+
this.bgLine?.disable();
|
|
3353
|
+
}
|
|
3354
|
+
dispose() {
|
|
3355
|
+
this.mainLine.dispose();
|
|
3356
|
+
this.bgLine?.dispose();
|
|
3357
|
+
}
|
|
3358
|
+
};
|
|
3359
|
+
//#endregion
|
|
3360
|
+
//#region src/lyric-player/dom/lyric-group.ts
|
|
3361
|
+
var LyricLineGroup = class extends LyricLineGroupBase {
|
|
3362
|
+
element;
|
|
3363
|
+
bgWrapper;
|
|
3364
|
+
lastIsActive;
|
|
3365
|
+
constructor(lyricPlayer, mainLine) {
|
|
3366
|
+
super(mainLine);
|
|
3367
|
+
this.lyricPlayer = lyricPlayer;
|
|
3368
|
+
this.element = document.createElement("div");
|
|
3369
|
+
this.element.className = lyric_player_module_default.lyricLineWrapper;
|
|
3370
|
+
this.element.appendChild(mainLine.getElement());
|
|
3371
|
+
this.posY.setPosition(window.innerHeight * 2);
|
|
3372
|
+
lyricPlayer.resizeObserver.observe(this.element);
|
|
3373
|
+
}
|
|
3374
|
+
get isInSight() {
|
|
3375
|
+
const t = this.posY.getCurrentPosition();
|
|
3376
|
+
let h = this.lyricPlayer.lyricGroupSize?.get(this)?.[1];
|
|
3377
|
+
if (h === void 0 || h === 0) h = this.element.clientHeight || 0;
|
|
3378
|
+
const pb = this.lyricPlayer.size[1];
|
|
3379
|
+
const ov = this.lyricPlayer.getOverscanPx();
|
|
3380
|
+
return !(t > pb + h + ov || t < -h - ov);
|
|
3381
|
+
}
|
|
3382
|
+
show() {
|
|
3383
|
+
if (!this.element.parentElement) {
|
|
3384
|
+
const playerEl = this.lyricPlayer.getElement();
|
|
3385
|
+
const groups = this.lyricPlayer.currentLyricGroups;
|
|
3386
|
+
const myIndex = groups.indexOf(this);
|
|
3387
|
+
let referenceNode = null;
|
|
3388
|
+
if (myIndex !== -1) {
|
|
3389
|
+
for (let i = myIndex + 1; i < groups.length; i++) if (groups[i].element.parentElement === playerEl) {
|
|
3390
|
+
referenceNode = groups[i].element;
|
|
3391
|
+
break;
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
playerEl.insertBefore(this.element, referenceNode);
|
|
3395
|
+
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3396
|
+
}
|
|
3397
|
+
this.mainLine.show();
|
|
3398
|
+
this.bgLine?.show();
|
|
3399
|
+
}
|
|
3400
|
+
hide() {
|
|
3401
|
+
if (this.element.parentElement) {
|
|
3402
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3403
|
+
this.element.remove();
|
|
3404
|
+
this.mainLine.teardownContent();
|
|
3405
|
+
this.bgLine?.teardownContent();
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
update(delta) {
|
|
3409
|
+
if (this.isInSight) this.show();
|
|
3410
|
+
else this.hide();
|
|
3411
|
+
super.update(delta);
|
|
3412
|
+
}
|
|
3413
|
+
addBgLine(bgLine) {
|
|
3414
|
+
if (this.bgLine) this.bgLine.dispose();
|
|
3415
|
+
if (this.bgWrapper) this.bgWrapper.remove();
|
|
3416
|
+
this.bgLine = bgLine;
|
|
3417
|
+
const bgStartTime = bgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;
|
|
3418
|
+
const mainStartTime = this.mainLine.getLine().words[0]?.startTime ?? this.mainLine.getLine().startTime;
|
|
3419
|
+
this.isBgFirst = bgStartTime < mainStartTime;
|
|
3420
|
+
if (this.mainLine.getLine().isDuet) bgLine.getElement().classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3421
|
+
this.bgWrapper = document.createElement("div");
|
|
3422
|
+
this.bgWrapper.className = lyric_player_module_default.bgWrapper;
|
|
3423
|
+
this.bgWrapper.appendChild(bgLine.getElement());
|
|
3424
|
+
if (!this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst) {
|
|
3425
|
+
this.bgWrapper.classList.add(lyric_player_module_default.bgWrapperTop);
|
|
3426
|
+
this.element.insertBefore(this.bgWrapper, this.mainLine.getElement());
|
|
3427
|
+
this.bgSlideY.setPosition(80);
|
|
3428
|
+
} else this.element.appendChild(this.bgWrapper);
|
|
3429
|
+
}
|
|
3430
|
+
renderStyles() {
|
|
3431
|
+
const y = this.posY.getCurrentPosition().toFixed(1);
|
|
3432
|
+
this.element.style.transform = `translateY(${y}px)`;
|
|
3433
|
+
this.element.style.opacity = this.opacity.toString();
|
|
3434
|
+
this.element.style.filter = `blur(${Math.min(5, this.blur)}px)`;
|
|
3435
|
+
if (!this.lyricPlayer.getEnableSpring()) this.element.style.transitionDelay = `${this.delay}ms`;
|
|
3436
|
+
if (this.bgWrapper) {
|
|
3437
|
+
if (this.lastIsActive !== this.isActive) {
|
|
3438
|
+
this.lastIsActive = this.isActive;
|
|
3439
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperActive, this.isActive);
|
|
3440
|
+
}
|
|
3441
|
+
const slideY = this.bgSlideY.getCurrentPosition();
|
|
3442
|
+
const slideYStr = slideY.toFixed(1);
|
|
3443
|
+
const activeProgress = clamp01(1 - Math.abs(slideY) / 80);
|
|
3444
|
+
const scaleStr = (.8 + activeProgress * .2).toFixed(3);
|
|
3445
|
+
this.bgWrapper.style.transform = `translateY(${slideYStr}%) scale(${scaleStr})`;
|
|
3446
|
+
const shouldBgFirst = !this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst;
|
|
3447
|
+
if (shouldBgFirst) {
|
|
3448
|
+
const currentMarginTop = -(this.bgWrapper.clientHeight || 0) * (1 - activeProgress);
|
|
3449
|
+
this.bgWrapper.style.marginTop = `${currentMarginTop.toFixed(1)}px`;
|
|
3450
|
+
} else this.bgWrapper.style.marginTop = "";
|
|
3451
|
+
const isHidden = slideYStr === (shouldBgFirst ? "80.0" : "-80.0") && !this.isActive;
|
|
3452
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperHidden, isHidden);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
dispose() {
|
|
3456
|
+
super.dispose();
|
|
3457
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3458
|
+
this.element.remove();
|
|
3459
|
+
}
|
|
3460
|
+
};
|
|
3461
|
+
//#endregion
|
|
3262
3462
|
//#region src/utils/is-cjk.ts
|
|
3263
3463
|
const isCJK = (char) => {
|
|
3264
3464
|
return /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u.test(char);
|
|
@@ -3275,10 +3475,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3275
3475
|
blur = 0;
|
|
3276
3476
|
opacity = 1;
|
|
3277
3477
|
delay = 0;
|
|
3278
|
-
lineTransforms = {
|
|
3279
|
-
posY: new Spring(0),
|
|
3280
|
-
scale: new Spring(100)
|
|
3281
|
-
};
|
|
3478
|
+
lineTransforms = { scale: new Spring(100) };
|
|
3282
3479
|
/**
|
|
3283
3480
|
* 用于 CJK 词语边界检测的分词器
|
|
3284
3481
|
*/
|
|
@@ -3288,9 +3485,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3288
3485
|
* 用于正确处理 emoji、复合字符等
|
|
3289
3486
|
*/
|
|
3290
3487
|
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;
|
|
3488
|
+
setTransform(scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3294
3489
|
this.scale = scale;
|
|
3295
3490
|
this.opacity = opacity;
|
|
3296
3491
|
this.blur = blur;
|
|
@@ -3768,12 +3963,9 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3768
3963
|
super();
|
|
3769
3964
|
this.lyricPlayer = lyricPlayer;
|
|
3770
3965
|
this.lyricLine = lyricLine;
|
|
3771
|
-
this._prevParentEl = lyricPlayer.getElement();
|
|
3772
|
-
lyricPlayer.resizeObserver.observe(this.element);
|
|
3773
3966
|
this.element.setAttribute("class", lyric_player_module_default.lyricLine);
|
|
3774
3967
|
if (this.lyricLine.isBG) this.element.classList.add(lyric_player_module_default.lyricBgLine);
|
|
3775
3968
|
if (this.lyricLine.isDuet) this.element.classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3776
|
-
this.lineTransforms.posY.setPosition(window.innerHeight * 2);
|
|
3777
3969
|
this.element.appendChild(document.createElement("div"));
|
|
3778
3970
|
this.element.appendChild(document.createElement("div"));
|
|
3779
3971
|
this.element.appendChild(document.createElement("div"));
|
|
@@ -3905,34 +4097,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3905
4097
|
getLine() {
|
|
3906
4098
|
return this.lyricLine;
|
|
3907
4099
|
}
|
|
3908
|
-
_prevParentEl;
|
|
3909
4100
|
lastStyle = "";
|
|
3910
4101
|
show() {
|
|
3911
|
-
if (!this.element.parentElement) {
|
|
3912
|
-
this._prevParentEl.appendChild(this.element);
|
|
3913
|
-
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3914
|
-
}
|
|
3915
4102
|
if (!this.built) {
|
|
3916
4103
|
this.rebuildElement();
|
|
3917
4104
|
this.built = true;
|
|
3918
4105
|
this.updateMaskImageSync();
|
|
3919
4106
|
}
|
|
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
4107
|
}
|
|
3932
4108
|
rebuildStyle() {
|
|
3933
4109
|
let style = "";
|
|
3934
|
-
style += `transform:
|
|
3935
|
-
if (!this.lyricPlayer.getEnableSpring()
|
|
4110
|
+
style += `transform: scale(${(this.lineTransforms.scale.getCurrentPosition() / 100).toFixed(4)});`;
|
|
4111
|
+
if (!this.lyricPlayer.getEnableSpring()) style += `transition-delay:${this.delay}ms;`;
|
|
3936
4112
|
style += `filter:blur(${Math.min(5, this.blur)}px);`;
|
|
3937
4113
|
if (style !== this.lastStyle) {
|
|
3938
4114
|
this.lastStyle = style;
|
|
@@ -4375,25 +4551,19 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4375
4551
|
this.element.style.setProperty("--bright-mask-alpha", this.currentBrightAlpha.toFixed(3));
|
|
4376
4552
|
this.element.style.setProperty("--dark-mask-alpha", this.currentDarkAlpha.toFixed(3));
|
|
4377
4553
|
}
|
|
4378
|
-
setTransform(
|
|
4379
|
-
super.setTransform(
|
|
4554
|
+
setTransform(scale = this.scale, opacity = 1, blur = 0, force = false, delay = 0, mode = LyricLineRenderMode.SOLID) {
|
|
4555
|
+
super.setTransform(scale, opacity, blur, force, delay);
|
|
4380
4556
|
this.renderMode = mode;
|
|
4381
|
-
const beforeInSight = this.isInSight;
|
|
4382
4557
|
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
4383
|
-
this.top =
|
|
4558
|
+
this.top = 0;
|
|
4384
4559
|
this.scale = scale;
|
|
4385
4560
|
this.delay = delay * 1e3 | 0;
|
|
4386
4561
|
const main = this.element.children[0];
|
|
4387
4562
|
main.style.opacity = `${opacity}`;
|
|
4388
4563
|
if (force || !enableSpring) {
|
|
4389
4564
|
this.blur = Math.min(32, blur);
|
|
4390
|
-
this.lineTransforms.posY.setPosition(top);
|
|
4391
4565
|
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();
|
|
4566
|
+
this.rebuildStyle();
|
|
4397
4567
|
const currentScale = this.lineTransforms.scale.getCurrentPosition();
|
|
4398
4568
|
this.updateMaskAlphaTargets(currentScale / 100);
|
|
4399
4569
|
this.currentBrightAlpha = this.targetBrightAlpha;
|
|
@@ -4401,21 +4571,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4401
4571
|
this.element.style.setProperty("--bright-mask-alpha", String(this.currentBrightAlpha));
|
|
4402
4572
|
this.element.style.setProperty("--dark-mask-alpha", String(this.currentDarkAlpha));
|
|
4403
4573
|
} else {
|
|
4404
|
-
this.lineTransforms.posY.setTargetPosition(top, delay);
|
|
4405
4574
|
this.lineTransforms.scale.setTargetPosition(scale);
|
|
4406
4575
|
if (this.blur !== Math.min(5, blur)) {
|
|
4407
4576
|
this.blur = Math.min(5, blur);
|
|
4408
|
-
|
|
4409
|
-
this.element.style.filter = `blur(${roundedBlur}px)`;
|
|
4577
|
+
this.element.style.filter = `blur(${blur.toFixed(3)}px)`;
|
|
4410
4578
|
}
|
|
4411
4579
|
}
|
|
4412
4580
|
}
|
|
4413
4581
|
update(delta = 0) {
|
|
4414
4582
|
if (!this.lyricPlayer.getEnableSpring()) return;
|
|
4415
|
-
this.lineTransforms.posY.update(delta);
|
|
4416
4583
|
this.lineTransforms.scale.update(delta);
|
|
4417
|
-
|
|
4418
|
-
|
|
4584
|
+
this.rebuildStyle();
|
|
4585
|
+
if (!this.built) return;
|
|
4419
4586
|
const currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;
|
|
4420
4587
|
this.updateMaskAlphaTargets(currentScale);
|
|
4421
4588
|
this.applyAlphaToDom(delta);
|
|
@@ -4423,13 +4590,11 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4423
4590
|
_getDebugTargetPos() {
|
|
4424
4591
|
return `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;
|
|
4425
4592
|
}
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
const ov = this.lyricPlayer.getOverscanPx();
|
|
4432
|
-
return !(t > pb + h + ov || b < -h - ov);
|
|
4593
|
+
teardownContent() {
|
|
4594
|
+
if (this.built) {
|
|
4595
|
+
this.disposeElements();
|
|
4596
|
+
this.built = false;
|
|
4597
|
+
}
|
|
4433
4598
|
}
|
|
4434
4599
|
disposeElements() {
|
|
4435
4600
|
this.balancer?.reset();
|
|
@@ -4477,7 +4642,7 @@ var LyricLineMouseEvent = class extends MouseEvent {
|
|
|
4477
4642
|
* 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
|
|
4478
4643
|
*/
|
|
4479
4644
|
var DomLyricPlayer = class extends LyricPlayerBase {
|
|
4480
|
-
|
|
4645
|
+
currentLyricGroups = [];
|
|
4481
4646
|
onResize() {
|
|
4482
4647
|
const computedStyles = getComputedStyle(this.element);
|
|
4483
4648
|
this._baseFontSize = Number.parseFloat(computedStyles.fontSize);
|
|
@@ -4514,7 +4679,10 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4514
4679
|
rebuildStyle() {}
|
|
4515
4680
|
setWordFadeWidth(value = .5) {
|
|
4516
4681
|
super.setWordFadeWidth(value);
|
|
4517
|
-
for (const
|
|
4682
|
+
for (const group of this.currentLyricGroups) {
|
|
4683
|
+
group.mainLine.updateMaskImageSync();
|
|
4684
|
+
group.bgLine?.updateMaskImageSync();
|
|
4685
|
+
}
|
|
4518
4686
|
}
|
|
4519
4687
|
/**
|
|
4520
4688
|
* 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误
|
|
@@ -4526,36 +4694,52 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4526
4694
|
if (this.hasDuetLine) this.element.classList.add(lyric_player_module_default.hasDuetLine);
|
|
4527
4695
|
else this.element.classList.remove(lyric_player_module_default.hasDuetLine);
|
|
4528
4696
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${initialTime}`);
|
|
4529
|
-
for (const
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4697
|
+
for (const group of this.currentLyricGroups) {
|
|
4698
|
+
const linesToDispose = [group.mainLine, group.bgLine].filter((line) => !!line);
|
|
4699
|
+
for (const line of linesToDispose) {
|
|
4700
|
+
line.removeMouseEventListener("click", this.onLineClickedHandler);
|
|
4701
|
+
line.removeMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4702
|
+
}
|
|
4703
|
+
group.dispose();
|
|
4533
4704
|
}
|
|
4534
|
-
this.
|
|
4705
|
+
this.currentLyricGroups = [];
|
|
4706
|
+
let currentGroup = null;
|
|
4707
|
+
for (let i = 0; i < this.processedLines.length; i++) {
|
|
4708
|
+
const line = this.processedLines[i];
|
|
4535
4709
|
const lineEl = new LyricLineEl(this, line);
|
|
4536
4710
|
lineEl.addMouseEventListener("click", this.onLineClickedHandler);
|
|
4537
4711
|
lineEl.addMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4538
4712
|
this.lyricLinesIndexes.set(lineEl, i);
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4713
|
+
if (!line.isBG || !currentGroup) {
|
|
4714
|
+
currentGroup = new LyricLineGroup(this, lineEl);
|
|
4715
|
+
this.currentLyricGroups.push(currentGroup);
|
|
4716
|
+
this.lyricGroupElementMap.set(currentGroup.element, currentGroup);
|
|
4717
|
+
} else currentGroup.addBgLine(lineEl);
|
|
4718
|
+
}
|
|
4542
4719
|
this.setLinePosXSpringParams({});
|
|
4543
4720
|
this.setLinePosYSpringParams({});
|
|
4544
4721
|
this.setLineScaleSpringParams({});
|
|
4722
|
+
this.setCurrentTime(initialTime, true);
|
|
4545
4723
|
this.calcLayout(true);
|
|
4546
4724
|
this.update(0);
|
|
4547
4725
|
}
|
|
4548
4726
|
pause() {
|
|
4549
4727
|
super.pause();
|
|
4550
|
-
this.element.classList.remove(
|
|
4728
|
+
this.element.classList.remove(lyric_player_module_default.playing);
|
|
4551
4729
|
this.interludeDots.pause();
|
|
4552
|
-
for (const
|
|
4730
|
+
for (const group of this.currentLyricGroups) {
|
|
4731
|
+
group.mainLine.pause();
|
|
4732
|
+
group.bgLine?.pause();
|
|
4733
|
+
}
|
|
4553
4734
|
}
|
|
4554
4735
|
resume() {
|
|
4555
4736
|
super.resume();
|
|
4556
|
-
this.element.classList.add(
|
|
4737
|
+
this.element.classList.add(lyric_player_module_default.playing);
|
|
4557
4738
|
this.interludeDots.resume();
|
|
4558
|
-
for (const
|
|
4739
|
+
for (const group of this.currentLyricGroups) {
|
|
4740
|
+
group.mainLine.resume();
|
|
4741
|
+
group.bgLine?.resume();
|
|
4742
|
+
}
|
|
4559
4743
|
}
|
|
4560
4744
|
update(delta = 0) {
|
|
4561
4745
|
if (!this.timelineState.initialLayoutFinished) return;
|
|
@@ -4563,12 +4747,12 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4563
4747
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${this.timelineState.currentTime}`);
|
|
4564
4748
|
if (!this.isPageVisible) return;
|
|
4565
4749
|
const deltaS = delta / 1e3;
|
|
4566
|
-
for (const
|
|
4750
|
+
for (const group of this.currentLyricGroups) group.update(deltaS);
|
|
4567
4751
|
}
|
|
4568
4752
|
dispose() {
|
|
4569
4753
|
super.dispose();
|
|
4570
4754
|
this.element.remove();
|
|
4571
|
-
for (const
|
|
4755
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4572
4756
|
this.bottomLine.dispose();
|
|
4573
4757
|
this.interludeDots.dispose();
|
|
4574
4758
|
}
|