@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.mjs
CHANGED
|
@@ -1706,6 +1706,10 @@ var BackgroundRender = class BackgroundRender {
|
|
|
1706
1706
|
//#region src/styles/lyric-player.module.css
|
|
1707
1707
|
var lyric_player_module_default = {
|
|
1708
1708
|
"active": "FmKaba_active",
|
|
1709
|
+
"bgWrapper": "FmKaba_bgWrapper",
|
|
1710
|
+
"bgWrapperActive": "FmKaba_bgWrapperActive",
|
|
1711
|
+
"bgWrapperHidden": "FmKaba_bgWrapperHidden",
|
|
1712
|
+
"bgWrapperTop": "FmKaba_bgWrapperTop",
|
|
1709
1713
|
"bottomLine": "FmKaba_bottomLine",
|
|
1710
1714
|
"dirty": "FmKaba_dirty",
|
|
1711
1715
|
"disableSpring": "FmKaba_disableSpring",
|
|
@@ -1718,8 +1722,10 @@ var lyric_player_module_default = {
|
|
|
1718
1722
|
"lyricBgLine": "FmKaba_lyricBgLine",
|
|
1719
1723
|
"lyricDuetLine": "FmKaba_lyricDuetLine",
|
|
1720
1724
|
"lyricLine": "FmKaba_lyricLine",
|
|
1725
|
+
"lyricLineWrapper": "FmKaba_lyricLineWrapper",
|
|
1721
1726
|
"lyricMainLine": "FmKaba_lyricMainLine",
|
|
1722
1727
|
"lyricSubLine": "FmKaba_lyricSubLine",
|
|
1728
|
+
"playing": "FmKaba_playing",
|
|
1723
1729
|
"romanWord": "FmKaba_romanWord",
|
|
1724
1730
|
"rubyWord": "FmKaba_rubyWord",
|
|
1725
1731
|
"tmpDisableTransition": "FmKaba_tmpDisableTransition",
|
|
@@ -1820,27 +1826,31 @@ function cleanUnintentionalOverlaps(lines) {
|
|
|
1820
1826
|
* 尝试让歌词提前最多 600ms 开始,如果有重叠则尝试最多提前 400ms 或上一行时长的 30%
|
|
1821
1827
|
*/
|
|
1822
1828
|
function tryAdvanceStartTime(lines) {
|
|
1823
|
-
|
|
1829
|
+
const defaultAdvanceAmount = 600;
|
|
1830
|
+
const fallbackAdvanceAmount = 400;
|
|
1831
|
+
const fallbackAdvanceRatio = .3;
|
|
1832
|
+
let prevLineStartTime = 0;
|
|
1833
|
+
let prevLineEndTime = 0;
|
|
1834
|
+
let prevMainGroupStartTime = 0;
|
|
1835
|
+
let prevMainGroupEndTime = 0;
|
|
1836
|
+
let hasPrevLine = false;
|
|
1837
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1824
1838
|
const line = lines[i];
|
|
1825
1839
|
if (line.isBG) continue;
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
let prevIdx = i - 1;
|
|
1829
|
-
if (lines[prevIdx].isBG) prevIdx--;
|
|
1830
|
-
if (prevIdx >= 0) prevLine = lines[prevIdx];
|
|
1831
|
-
}
|
|
1840
|
+
const originalStartTime = line.startTime;
|
|
1841
|
+
const originalEndTime = line.endTime;
|
|
1832
1842
|
let targetAdvanceAmount = 0;
|
|
1833
1843
|
let safeBoundary = 0;
|
|
1834
|
-
if (
|
|
1835
|
-
targetAdvanceAmount =
|
|
1836
|
-
safeBoundary =
|
|
1844
|
+
if (hasPrevLine) if (originalStartTime >= prevLineEndTime) {
|
|
1845
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1846
|
+
safeBoundary = prevMainGroupEndTime;
|
|
1837
1847
|
} else {
|
|
1838
|
-
targetAdvanceAmount =
|
|
1839
|
-
const prevDuration =
|
|
1840
|
-
safeBoundary =
|
|
1848
|
+
targetAdvanceAmount = fallbackAdvanceAmount;
|
|
1849
|
+
const prevDuration = prevLineEndTime - prevLineStartTime;
|
|
1850
|
+
safeBoundary = prevLineStartTime + prevDuration * fallbackAdvanceRatio;
|
|
1841
1851
|
}
|
|
1842
1852
|
else {
|
|
1843
|
-
targetAdvanceAmount =
|
|
1853
|
+
targetAdvanceAmount = defaultAdvanceAmount;
|
|
1844
1854
|
safeBoundary = 0;
|
|
1845
1855
|
}
|
|
1846
1856
|
const targetTime = line.startTime - targetAdvanceAmount;
|
|
@@ -1848,6 +1858,20 @@ function tryAdvanceStartTime(lines) {
|
|
|
1848
1858
|
if (newStartTime < line.startTime) line.startTime = newStartTime;
|
|
1849
1859
|
const nextLine = lines[i + 1];
|
|
1850
1860
|
if (nextLine?.isBG) nextLine.startTime = line.startTime;
|
|
1861
|
+
if (hasPrevLine) if (originalStartTime < prevMainGroupEndTime && originalEndTime > prevMainGroupStartTime) {
|
|
1862
|
+
prevMainGroupStartTime = Math.min(prevMainGroupStartTime, originalStartTime);
|
|
1863
|
+
prevMainGroupEndTime = Math.max(prevMainGroupEndTime, originalEndTime);
|
|
1864
|
+
} else {
|
|
1865
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1866
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1867
|
+
}
|
|
1868
|
+
else {
|
|
1869
|
+
prevMainGroupStartTime = originalStartTime;
|
|
1870
|
+
prevMainGroupEndTime = originalEndTime;
|
|
1871
|
+
}
|
|
1872
|
+
prevLineStartTime = originalStartTime;
|
|
1873
|
+
prevLineEndTime = originalEndTime;
|
|
1874
|
+
hasPrevLine = true;
|
|
1851
1875
|
}
|
|
1852
1876
|
}
|
|
1853
1877
|
/**
|
|
@@ -2247,19 +2271,19 @@ const LayoutAlignAnchor = {
|
|
|
2247
2271
|
function computeCurrentInterlude(input) {
|
|
2248
2272
|
const currentTime = input.currentTime + 20;
|
|
2249
2273
|
const currentIndex = input.scrollToIndex;
|
|
2250
|
-
const
|
|
2274
|
+
const groups = input.currentGroups;
|
|
2251
2275
|
const checkGap = (k) => {
|
|
2252
|
-
if (k < -1 || k >=
|
|
2253
|
-
const
|
|
2254
|
-
const
|
|
2255
|
-
const gapStart =
|
|
2256
|
-
const gapEnd = Math.max(gapStart,
|
|
2257
|
-
if (gapEnd - gapStart < 4e3) return;
|
|
2276
|
+
if (k < -1 || k >= groups.length - 1) return void 0;
|
|
2277
|
+
const prevGroup = k === -1 ? null : groups[k];
|
|
2278
|
+
const nextGroup = groups[k + 1];
|
|
2279
|
+
const gapStart = prevGroup ? prevGroup.endTime : 0;
|
|
2280
|
+
const gapEnd = Math.max(gapStart, nextGroup.startTime - 250);
|
|
2281
|
+
if (gapEnd - gapStart < 4e3) return void 0;
|
|
2258
2282
|
if (gapEnd > currentTime && gapStart < currentTime) return {
|
|
2259
2283
|
startTime: Math.max(gapStart, currentTime),
|
|
2260
2284
|
endTime: gapEnd,
|
|
2261
2285
|
anchorLineIndex: k,
|
|
2262
|
-
isNextDuet:
|
|
2286
|
+
isNextDuet: nextGroup.mainLine.getLine().isDuet
|
|
2263
2287
|
};
|
|
2264
2288
|
};
|
|
2265
2289
|
return checkGap(currentIndex - 1) || checkGap(currentIndex) || checkGap(currentIndex + 1);
|
|
@@ -2272,8 +2296,8 @@ function computeCurrentInterlude(input) {
|
|
|
2272
2296
|
* - 普通播放时根据相邻歌词的时间间隔动态调整 stiffness / damping
|
|
2273
2297
|
*/
|
|
2274
2298
|
function computeLinePosYSpringParams(input) {
|
|
2275
|
-
const { enabled,
|
|
2276
|
-
if (!enabled ||
|
|
2299
|
+
const { enabled, currentGroups, scrollToIndex, isSeeking, isInterludeActive } = input;
|
|
2300
|
+
if (!enabled || currentGroups.length === 0) return { shouldUpdate: false };
|
|
2277
2301
|
if (isSeeking || isInterludeActive) return {
|
|
2278
2302
|
shouldUpdate: true,
|
|
2279
2303
|
params: {
|
|
@@ -2281,10 +2305,10 @@ function computeLinePosYSpringParams(input) {
|
|
|
2281
2305
|
damping: 15
|
|
2282
2306
|
}
|
|
2283
2307
|
};
|
|
2284
|
-
const
|
|
2285
|
-
const
|
|
2286
|
-
if (!
|
|
2287
|
-
const interval =
|
|
2308
|
+
const currentGroup = currentGroups[scrollToIndex];
|
|
2309
|
+
const prevGroup = currentGroups[scrollToIndex - 1];
|
|
2310
|
+
if (!currentGroup || !prevGroup) return { shouldUpdate: false };
|
|
2311
|
+
const interval = currentGroup.startTime - prevGroup.startTime;
|
|
2288
2312
|
const MIN_INTERVAL = 100;
|
|
2289
2313
|
const MAX_INTERVAL = 800;
|
|
2290
2314
|
const clampedInterval = clamp(interval, MIN_INTERVAL, MAX_INTERVAL);
|
|
@@ -2302,38 +2326,33 @@ function computeLinePosYSpringParams(input) {
|
|
|
2302
2326
|
};
|
|
2303
2327
|
}
|
|
2304
2328
|
/**
|
|
2305
|
-
*
|
|
2329
|
+
* 计算一组歌词在当前布局中的视觉呈现参数。
|
|
2306
2330
|
*
|
|
2307
2331
|
* 根据播放状态、缓冲状态、布局模式与间奏信息,
|
|
2308
|
-
*
|
|
2332
|
+
* 生成一组歌词最终应使用的活跃状态、不透明度与模糊值。
|
|
2309
2333
|
*/
|
|
2310
|
-
function
|
|
2311
|
-
const {
|
|
2312
|
-
const isActive = hasBuffered ||
|
|
2334
|
+
function computeGroupPresentation(input) {
|
|
2335
|
+
const { groupIndex, scrollToIndex, latestIndex, hasBuffered, hidePassedLines, isPlaying, isNonDynamic, enableBlur, isUserScrolling, isCompact, interlude } = input;
|
|
2336
|
+
const isActive = hasBuffered || groupIndex >= scrollToIndex && groupIndex < latestIndex;
|
|
2313
2337
|
const blurLevel = computeLineBlur({
|
|
2314
2338
|
enableBlur,
|
|
2315
2339
|
isUserScrolling,
|
|
2316
2340
|
isActive,
|
|
2317
|
-
itemIndex:
|
|
2341
|
+
itemIndex: groupIndex,
|
|
2318
2342
|
scrollToIndex,
|
|
2319
2343
|
latestIndex,
|
|
2320
2344
|
isCompact
|
|
2321
2345
|
});
|
|
2322
2346
|
let targetOpacity;
|
|
2323
|
-
if (hidePassedLines) if (
|
|
2347
|
+
if (hidePassedLines) if (groupIndex < (interlude ? interlude.anchorLineIndex + 1 : scrollToIndex) && isPlaying) targetOpacity = 1e-4;
|
|
2324
2348
|
else if (hasBuffered) targetOpacity = .85;
|
|
2325
2349
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2326
2350
|
else if (hasBuffered) targetOpacity = .85;
|
|
2327
2351
|
else targetOpacity = isNonDynamic ? .2 : 1;
|
|
2328
|
-
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
2329
|
-
let targetScale = 100;
|
|
2330
|
-
if (!isActive && isPlaying) targetScale = line.isBG ? 75 : SCALE_ASPECT;
|
|
2331
2352
|
return {
|
|
2332
2353
|
isActive,
|
|
2333
2354
|
targetOpacity,
|
|
2334
|
-
|
|
2335
|
-
blurLevel,
|
|
2336
|
-
renderMode: isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID
|
|
2355
|
+
blurLevel
|
|
2337
2356
|
};
|
|
2338
2357
|
}
|
|
2339
2358
|
/**
|
|
@@ -2489,50 +2508,29 @@ const eqSet = (xs, ys) => xs.size === ys.size && [...xs].every((x) => ys.has(x))
|
|
|
2489
2508
|
* - 根据新的热行状态和已有的缓冲行状态,计算出应移除的缓冲行 ID
|
|
2490
2509
|
*/
|
|
2491
2510
|
function computePlayerTimeState(input) {
|
|
2492
|
-
const { time,
|
|
2493
|
-
const
|
|
2511
|
+
const { time, currentGroups, timelineState: { hotGroups, bufferedGroups } } = input;
|
|
2512
|
+
const nextHotGroups = new Set(hotGroups);
|
|
2494
2513
|
const addedIds = /* @__PURE__ */ new Set();
|
|
2495
2514
|
const removedHotIds = /* @__PURE__ */ new Set();
|
|
2496
2515
|
const removedBufferedIds = /* @__PURE__ */ new Set();
|
|
2497
|
-
for (const lastHotId of
|
|
2498
|
-
const
|
|
2499
|
-
if (!
|
|
2500
|
-
|
|
2501
|
-
removedHotIds.add(lastHotId);
|
|
2502
|
-
continue;
|
|
2503
|
-
}
|
|
2504
|
-
if (line.isBG) continue;
|
|
2505
|
-
const nextLine = processedLines[lastHotId + 1];
|
|
2506
|
-
if (nextLine?.isBG) {
|
|
2507
|
-
const nextMainLine = processedLines[lastHotId + 2];
|
|
2508
|
-
const startTime = Math.min(line.startTime, nextLine.startTime);
|
|
2509
|
-
const endTime = Math.min(Math.max(line.endTime, nextMainLine?.startTime ?? Number.MAX_VALUE), Math.max(line.endTime, nextLine.endTime));
|
|
2510
|
-
if (time < startTime || endTime <= time) {
|
|
2511
|
-
nextHotLines.delete(lastHotId);
|
|
2512
|
-
removedHotIds.add(lastHotId);
|
|
2513
|
-
nextHotLines.delete(lastHotId + 1);
|
|
2514
|
-
removedHotIds.add(lastHotId + 1);
|
|
2515
|
-
}
|
|
2516
|
-
} else if (time < line.startTime || line.endTime <= time) {
|
|
2517
|
-
nextHotLines.delete(lastHotId);
|
|
2516
|
+
for (const lastHotId of hotGroups) {
|
|
2517
|
+
const group = currentGroups[lastHotId];
|
|
2518
|
+
if (!group || time < group.startTime || group.endTime <= time) {
|
|
2519
|
+
nextHotGroups.delete(lastHotId);
|
|
2518
2520
|
removedHotIds.add(lastHotId);
|
|
2519
2521
|
}
|
|
2520
2522
|
}
|
|
2521
|
-
for (let id = 0; id <
|
|
2522
|
-
const
|
|
2523
|
-
if (!
|
|
2524
|
-
if (
|
|
2525
|
-
|
|
2523
|
+
for (let id = 0; id < currentGroups.length; id++) {
|
|
2524
|
+
const group = currentGroups[id];
|
|
2525
|
+
if (!group) continue;
|
|
2526
|
+
if (group.startTime <= time && group.endTime > time && !nextHotGroups.has(id)) {
|
|
2527
|
+
nextHotGroups.add(id);
|
|
2526
2528
|
addedIds.add(id);
|
|
2527
|
-
if (processedLines[id + 1]?.isBG) {
|
|
2528
|
-
nextHotLines.add(id + 1);
|
|
2529
|
-
addedIds.add(id + 1);
|
|
2530
|
-
}
|
|
2531
2529
|
}
|
|
2532
2530
|
}
|
|
2533
|
-
for (const id of
|
|
2531
|
+
for (const id of bufferedGroups) if (!nextHotGroups.has(id)) removedBufferedIds.add(id);
|
|
2534
2532
|
return {
|
|
2535
|
-
|
|
2533
|
+
nextHotGroups,
|
|
2536
2534
|
addedIds,
|
|
2537
2535
|
removedHotIds,
|
|
2538
2536
|
removedBufferedIds
|
|
@@ -2544,10 +2542,10 @@ function computePlayerTimeState(input) {
|
|
|
2544
2542
|
* 若当前仍存在缓冲行,则优先对齐到最靠前的缓冲行;
|
|
2545
2543
|
* 否则对齐到第一条开始时间不小于当前时间的歌词行。
|
|
2546
2544
|
*/
|
|
2547
|
-
function pickScrollToIndexForSeek(time,
|
|
2548
|
-
if (
|
|
2549
|
-
const foundIndex =
|
|
2550
|
-
return foundIndex === -1 ?
|
|
2545
|
+
function pickScrollToIndexForSeek(time, currentGroups, bufferedGroups) {
|
|
2546
|
+
if (bufferedGroups.size > 0) return Math.min(...bufferedGroups);
|
|
2547
|
+
const foundIndex = currentGroups.findIndex((group) => group.startTime >= time);
|
|
2548
|
+
return foundIndex === -1 ? currentGroups.length : foundIndex;
|
|
2551
2549
|
}
|
|
2552
2550
|
/**
|
|
2553
2551
|
* 提交时间线状态转移的纯函数。
|
|
@@ -2557,45 +2555,45 @@ function pickScrollToIndexForSeek(time, processedLines, bufferedLines) {
|
|
|
2557
2555
|
* 是否需要重置用户滚动状态、是否需要触发布局。
|
|
2558
2556
|
*/
|
|
2559
2557
|
function commitPlayerTimeState(input) {
|
|
2560
|
-
const { timelineState, time,
|
|
2558
|
+
const { timelineState, time, currentGroups, hasBottomContent, stateResult } = input;
|
|
2561
2559
|
const { addedIds, removedHotIds, removedBufferedIds } = stateResult;
|
|
2562
2560
|
const { isSeeking } = timelineState;
|
|
2563
2561
|
timelineState.currentTime = time;
|
|
2564
|
-
timelineState.
|
|
2562
|
+
timelineState.hotGroups = stateResult.nextHotGroups;
|
|
2565
2563
|
let shouldLayout = false;
|
|
2566
2564
|
let shouldResetScroll = false;
|
|
2567
|
-
const
|
|
2568
|
-
const
|
|
2565
|
+
const groupsToEnable = [];
|
|
2566
|
+
const groupsToDisable = /* @__PURE__ */ new Set();
|
|
2569
2567
|
if (isSeeking) {
|
|
2570
|
-
timelineState.
|
|
2571
|
-
timelineState.scrollToIndex = pickScrollToIndexForSeek(time,
|
|
2572
|
-
for (const id of removedHotIds)
|
|
2573
|
-
for (const id of timelineState.
|
|
2574
|
-
for (const id of removedBufferedIds)
|
|
2568
|
+
timelineState.bufferedGroups = new Set([...timelineState.hotGroups]);
|
|
2569
|
+
timelineState.scrollToIndex = pickScrollToIndexForSeek(time, currentGroups, timelineState.bufferedGroups);
|
|
2570
|
+
for (const id of removedHotIds) groupsToDisable.add(id);
|
|
2571
|
+
for (const id of timelineState.hotGroups) groupsToEnable.push(id);
|
|
2572
|
+
for (const id of removedBufferedIds) groupsToDisable.add(id);
|
|
2575
2573
|
shouldResetScroll = true;
|
|
2576
2574
|
shouldLayout = true;
|
|
2577
2575
|
} else if (addedIds.size > 0) {
|
|
2578
2576
|
for (const id of addedIds) {
|
|
2579
|
-
timelineState.
|
|
2580
|
-
|
|
2577
|
+
timelineState.bufferedGroups.add(id);
|
|
2578
|
+
groupsToEnable.push(id);
|
|
2581
2579
|
}
|
|
2582
2580
|
for (const id of removedBufferedIds) {
|
|
2583
|
-
timelineState.
|
|
2584
|
-
|
|
2581
|
+
timelineState.bufferedGroups.delete(id);
|
|
2582
|
+
groupsToDisable.add(id);
|
|
2585
2583
|
}
|
|
2586
|
-
if (timelineState.
|
|
2584
|
+
if (timelineState.bufferedGroups.size > 0) timelineState.scrollToIndex = Math.min(...timelineState.bufferedGroups);
|
|
2587
2585
|
shouldLayout = true;
|
|
2588
|
-
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.
|
|
2589
|
-
for (const id of timelineState.
|
|
2590
|
-
if (timelineState.
|
|
2591
|
-
timelineState.
|
|
2592
|
-
|
|
2586
|
+
} else if (removedBufferedIds.size > 0 && eqSet(removedBufferedIds, timelineState.bufferedGroups)) {
|
|
2587
|
+
for (const id of timelineState.bufferedGroups) {
|
|
2588
|
+
if (timelineState.hotGroups.has(id)) continue;
|
|
2589
|
+
timelineState.bufferedGroups.delete(id);
|
|
2590
|
+
groupsToDisable.add(id);
|
|
2593
2591
|
}
|
|
2594
2592
|
shouldLayout = true;
|
|
2595
2593
|
}
|
|
2596
|
-
if (timelineState.
|
|
2597
|
-
if (time >=
|
|
2598
|
-
const targetIndex = hasBottomContent ?
|
|
2594
|
+
if (timelineState.bufferedGroups.size === 0 && currentGroups.length > 0) {
|
|
2595
|
+
if (time >= currentGroups[currentGroups.length - 1].endTime) {
|
|
2596
|
+
const targetIndex = hasBottomContent ? currentGroups.length : currentGroups.length - 1;
|
|
2599
2597
|
if (timelineState.scrollToIndex !== targetIndex) {
|
|
2600
2598
|
timelineState.scrollToIndex = targetIndex;
|
|
2601
2599
|
shouldLayout = true;
|
|
@@ -2606,8 +2604,8 @@ function commitPlayerTimeState(input) {
|
|
|
2606
2604
|
return {
|
|
2607
2605
|
shouldLayout,
|
|
2608
2606
|
shouldResetScroll,
|
|
2609
|
-
|
|
2610
|
-
|
|
2607
|
+
groupsToEnable,
|
|
2608
|
+
groupsToDisable: [...groupsToDisable]
|
|
2611
2609
|
};
|
|
2612
2610
|
}
|
|
2613
2611
|
//#endregion
|
|
@@ -2622,17 +2620,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2622
2620
|
timelineState = {
|
|
2623
2621
|
currentTime: 0,
|
|
2624
2622
|
lastCurrentTime: 0,
|
|
2625
|
-
|
|
2626
|
-
|
|
2623
|
+
hotGroups: /* @__PURE__ */ new Set(),
|
|
2624
|
+
bufferedGroups: /* @__PURE__ */ new Set(),
|
|
2627
2625
|
scrollToIndex: 0,
|
|
2628
2626
|
isSeeking: false,
|
|
2629
2627
|
isPlaying: true,
|
|
2630
2628
|
initialLayoutFinished: false
|
|
2631
2629
|
};
|
|
2632
2630
|
/** @internal */
|
|
2633
|
-
|
|
2634
|
-
/** @internal */
|
|
2635
|
-
lyricLineElementMap = /* @__PURE__ */ new WeakMap();
|
|
2631
|
+
lyricGroupElementMap = /* @__PURE__ */ new WeakMap();
|
|
2636
2632
|
currentLyricLines = [];
|
|
2637
2633
|
processedLines = [];
|
|
2638
2634
|
lyricLinesIndexes = /* @__PURE__ */ new WeakMap();
|
|
@@ -2664,10 +2660,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2664
2660
|
isScrolled: false,
|
|
2665
2661
|
isUserScrolling: false
|
|
2666
2662
|
};
|
|
2667
|
-
|
|
2663
|
+
currentLyricGroups = [];
|
|
2664
|
+
lyricGroupSize = /* @__PURE__ */ new WeakMap();
|
|
2668
2665
|
size = [0, 0];
|
|
2669
2666
|
isPageVisible = true;
|
|
2670
2667
|
optimizeOptions = {};
|
|
2668
|
+
/** 是否强制让背景人声行始终后置(即始终在主歌词下方显示,不前置背景人声) */
|
|
2669
|
+
alwaysPostpositionBackground = false;
|
|
2671
2670
|
posXSpringParams = {
|
|
2672
2671
|
mass: 1,
|
|
2673
2672
|
damping: 10,
|
|
@@ -2717,13 +2716,13 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2717
2716
|
shouldRelayout = true;
|
|
2718
2717
|
}
|
|
2719
2718
|
} else {
|
|
2720
|
-
const
|
|
2721
|
-
if (
|
|
2719
|
+
const groupObj = this.lyricGroupElementMap.get(entry.target);
|
|
2720
|
+
if (groupObj) {
|
|
2722
2721
|
const newSize = [entry.target.clientWidth, entry.target.clientHeight];
|
|
2723
|
-
const oldSize = this.
|
|
2722
|
+
const oldSize = this.lyricGroupSize.get(groupObj) ?? [0, 0];
|
|
2724
2723
|
if (newSize[0] !== oldSize[0] || newSize[1] !== oldSize[1]) {
|
|
2725
|
-
this.
|
|
2726
|
-
|
|
2724
|
+
this.lyricGroupSize.set(groupObj, newSize);
|
|
2725
|
+
groupObj.onLineSizeChange(newSize);
|
|
2727
2726
|
shouldRelayout = true;
|
|
2728
2727
|
}
|
|
2729
2728
|
}
|
|
@@ -2849,7 +2848,7 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2849
2848
|
}
|
|
2850
2849
|
}
|
|
2851
2850
|
rebuildLyricLines() {
|
|
2852
|
-
for (const
|
|
2851
|
+
for (const group of this.currentLyricGroups) group.rebuildAllLines();
|
|
2853
2852
|
}
|
|
2854
2853
|
/**
|
|
2855
2854
|
* 根据当前配置处理不雅用语单词
|
|
@@ -2951,11 +2950,11 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2951
2950
|
break;
|
|
2952
2951
|
}
|
|
2953
2952
|
this.hasDuetLine = this.processedLines.some((line) => line.isDuet);
|
|
2954
|
-
for (const
|
|
2953
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
2954
|
+
this.currentLyricGroups = [];
|
|
2955
2955
|
this.interludeDots.setInterlude(void 0);
|
|
2956
|
-
this.timelineState.
|
|
2957
|
-
this.timelineState.
|
|
2958
|
-
this.setCurrentTime(0, true);
|
|
2956
|
+
this.timelineState.hotGroups.clear();
|
|
2957
|
+
this.timelineState.bufferedGroups.clear();
|
|
2959
2958
|
if (process.env.NODE_ENV !== "production") console.log("歌词处理完成", this);
|
|
2960
2959
|
}
|
|
2961
2960
|
/**
|
|
@@ -2981,19 +2980,19 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
2981
2980
|
if (!timelineState.initialLayoutFinished && !timelineState.isSeeking) return;
|
|
2982
2981
|
const stateResult = computePlayerTimeState({
|
|
2983
2982
|
time,
|
|
2984
|
-
|
|
2983
|
+
currentGroups: this.currentLyricGroups,
|
|
2985
2984
|
timelineState
|
|
2986
2985
|
});
|
|
2987
2986
|
const hasBottomContent = this.bottomLine.getElement().innerHTML.trim().length > 0;
|
|
2988
2987
|
const commitResult = commitPlayerTimeState({
|
|
2989
2988
|
timelineState,
|
|
2990
2989
|
time,
|
|
2991
|
-
|
|
2990
|
+
currentGroups: this.currentLyricGroups,
|
|
2992
2991
|
hasBottomContent,
|
|
2993
2992
|
stateResult
|
|
2994
2993
|
});
|
|
2995
|
-
for (const id of commitResult.
|
|
2996
|
-
for (const id of commitResult.
|
|
2994
|
+
for (const id of commitResult.groupsToDisable) this.currentLyricGroups[id]?.disable();
|
|
2995
|
+
for (const id of commitResult.groupsToEnable) this.currentLyricGroups[id]?.enable();
|
|
2997
2996
|
if (commitResult.shouldResetScroll) this.resetScroll();
|
|
2998
2997
|
if (commitResult.shouldLayout) this.calcLayout();
|
|
2999
2998
|
}
|
|
@@ -3018,14 +3017,14 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3018
3017
|
const interlude = computeCurrentInterlude({
|
|
3019
3018
|
currentTime: this.timelineState.currentTime,
|
|
3020
3019
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3021
|
-
|
|
3020
|
+
currentGroups: this.currentLyricGroups
|
|
3022
3021
|
});
|
|
3023
3022
|
const isInterludeActive = !!interlude;
|
|
3024
3023
|
if (this.layoutState.targetAlignIndex !== this.timelineState.scrollToIndex || this.layoutState.lastInterludeState !== isInterludeActive) {
|
|
3025
3024
|
this.layoutState.lastInterludeState = isInterludeActive;
|
|
3026
3025
|
const springParams = computeLinePosYSpringParams({
|
|
3027
3026
|
enabled: this.getEnableSpring(),
|
|
3028
|
-
|
|
3027
|
+
currentGroups: this.currentLyricGroups,
|
|
3029
3028
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3030
3029
|
isSeeking: this.timelineState.isSeeking,
|
|
3031
3030
|
isInterludeActive
|
|
@@ -3043,17 +3042,15 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3043
3042
|
if (interlude.anchorLineIndex !== -1) curPos -= totalInterludeHeight;
|
|
3044
3043
|
}
|
|
3045
3044
|
const LINE_HEIGHT_FALLBACK = this.size[1] / 5;
|
|
3046
|
-
const scrollOffset = this.
|
|
3045
|
+
const scrollOffset = this.currentLyricGroups.slice(0, targetAlignIndex).reduce((acc, group) => acc + (this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK), 0);
|
|
3047
3046
|
this.scrollState.scrollBoundary.minOffset = -scrollOffset;
|
|
3048
3047
|
curPos -= scrollOffset;
|
|
3049
3048
|
curPos += this.size[1] * this.layoutState.alignPosition;
|
|
3050
|
-
const
|
|
3049
|
+
const curGroup = this.currentLyricGroups[targetAlignIndex];
|
|
3051
3050
|
this.layoutState.targetAlignIndex = targetAlignIndex;
|
|
3052
|
-
const isBottomFocused = targetAlignIndex === this.
|
|
3051
|
+
const isBottomFocused = targetAlignIndex === this.currentLyricGroups.length;
|
|
3053
3052
|
this.bottomLine.setFocused(isBottomFocused);
|
|
3054
|
-
|
|
3055
|
-
if (curLine) targetLineHeight = this.lyricLinesSize.get(curLine)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3056
|
-
else if (isBottomFocused) targetLineHeight = this.bottomLine.lineSize[1];
|
|
3053
|
+
const targetLineHeight = curGroup ? this.lyricGroupSize.get(curGroup)?.[1] ?? LINE_HEIGHT_FALLBACK : isBottomFocused ? this.bottomLine.lineSize[1] : 0;
|
|
3057
3054
|
if (targetLineHeight > 0) switch (this.layoutState.alignAnchor) {
|
|
3058
3055
|
case LayoutAlignAnchor.Bottom:
|
|
3059
3056
|
curPos -= targetLineHeight;
|
|
@@ -3063,13 +3060,12 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3063
3060
|
break;
|
|
3064
3061
|
case LayoutAlignAnchor.Top: break;
|
|
3065
3062
|
}
|
|
3066
|
-
const latestIndex = Math.max(...this.timelineState.
|
|
3063
|
+
const latestIndex = Math.max(...this.timelineState.bufferedGroups);
|
|
3067
3064
|
let delay = 0;
|
|
3068
3065
|
let baseDelay = sync ? 0 : .05;
|
|
3069
3066
|
let setDots = false;
|
|
3070
|
-
this.
|
|
3071
|
-
const hasBuffered = this.timelineState.
|
|
3072
|
-
const line = lineObj.getLine();
|
|
3067
|
+
this.currentLyricGroups.forEach((group, i) => {
|
|
3068
|
+
const hasBuffered = this.timelineState.bufferedGroups.has(i);
|
|
3073
3069
|
const shouldShowDots = interlude && i === interlude.anchorLineIndex + 1;
|
|
3074
3070
|
if (!setDots && shouldShowDots) {
|
|
3075
3071
|
setDots = true;
|
|
@@ -3081,31 +3077,28 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3081
3077
|
curPos += this.layoutState.interludeDotsSize[1];
|
|
3082
3078
|
curPos += dotMargin;
|
|
3083
3079
|
}
|
|
3084
|
-
const presentation =
|
|
3085
|
-
|
|
3086
|
-
lineIndex: i,
|
|
3080
|
+
const presentation = computeGroupPresentation({
|
|
3081
|
+
groupIndex: i,
|
|
3087
3082
|
scrollToIndex: this.timelineState.scrollToIndex,
|
|
3088
3083
|
latestIndex,
|
|
3089
3084
|
hasBuffered,
|
|
3090
3085
|
hidePassedLines: this.hidePassedLines,
|
|
3091
3086
|
isPlaying: this.timelineState.isPlaying,
|
|
3092
3087
|
isNonDynamic: this.isNonDynamic,
|
|
3093
|
-
enableScale: this.enableScale,
|
|
3094
3088
|
enableBlur: this.enableBlur,
|
|
3095
3089
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
3096
3090
|
isCompact: window.innerWidth <= 1024,
|
|
3097
3091
|
interlude
|
|
3098
3092
|
});
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
else if (!line.isBG) curPos += this.lyricLinesSize.get(lineObj)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3093
|
+
group.setTransform(curPos, force, delay, presentation.isActive, presentation.targetOpacity, presentation.blurLevel);
|
|
3094
|
+
curPos += this.lyricGroupSize.get(group)?.[1] ?? LINE_HEIGHT_FALLBACK;
|
|
3102
3095
|
if (curPos >= 0 && !this.timelineState.isSeeking) {
|
|
3103
|
-
|
|
3096
|
+
delay += baseDelay;
|
|
3104
3097
|
if (i >= this.timelineState.scrollToIndex) baseDelay /= 1.05;
|
|
3105
3098
|
}
|
|
3106
3099
|
});
|
|
3107
3100
|
this.scrollState.scrollBoundary.maxOffset = curPos + this.scrollState.scrollOffset - this.size[1] / 2;
|
|
3108
|
-
const bottomIndex = this.
|
|
3101
|
+
const bottomIndex = this.currentLyricGroups.length;
|
|
3109
3102
|
const finalBottomBlur = computeLineBlur({
|
|
3110
3103
|
enableBlur: this.enableBlur,
|
|
3111
3104
|
isUserScrolling: this.scrollState.isUserScrolling,
|
|
@@ -3135,7 +3128,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3135
3128
|
...params
|
|
3136
3129
|
};
|
|
3137
3130
|
this.bottomLine.lineTransforms.posY.updateParams(this.posYSpringParams);
|
|
3138
|
-
for (const
|
|
3131
|
+
for (const group of this.currentLyricGroups) {
|
|
3132
|
+
group.posY.updateParams(this.posYSpringParams);
|
|
3133
|
+
group.bgSlideY.updateParams(this.posYSpringParams);
|
|
3134
|
+
}
|
|
3139
3135
|
}
|
|
3140
3136
|
/**
|
|
3141
3137
|
* 设置所有歌词行在缩放大小上的弹簧属性,包括重量、弹力和阻力。
|
|
@@ -3151,8 +3147,10 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3151
3147
|
...this.scaleForBGSpringParams,
|
|
3152
3148
|
...params
|
|
3153
3149
|
};
|
|
3154
|
-
for (const
|
|
3155
|
-
|
|
3150
|
+
for (const group of this.currentLyricGroups) {
|
|
3151
|
+
group.mainLine.lineTransforms.scale.updateParams(this.scaleSpringParams);
|
|
3152
|
+
group.bgLine?.lineTransforms.scale.updateParams(this.scaleForBGSpringParams);
|
|
3153
|
+
}
|
|
3156
3154
|
}
|
|
3157
3155
|
/**
|
|
3158
3156
|
* 暂停部分效果演出,目前会暂停播放间奏点的动画,且将背景歌词显示出来
|
|
@@ -3224,6 +3222,23 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3224
3222
|
getCurrentTime() {
|
|
3225
3223
|
return this.timelineState.currentTime;
|
|
3226
3224
|
}
|
|
3225
|
+
/**
|
|
3226
|
+
* 设置是否让背景人声行始终后置显示
|
|
3227
|
+
*
|
|
3228
|
+
* 默认情况下,如果背景歌词开始时间早于主歌词,会在主歌词上方展示;
|
|
3229
|
+
* 如果设置为 `true`,则无论时间顺序如何,背景歌词都会始终在主歌词下方展示
|
|
3230
|
+
* @param enable 是否启用始终后置
|
|
3231
|
+
*/
|
|
3232
|
+
setAlwaysPostpositionBackground(enable) {
|
|
3233
|
+
if (this.alwaysPostpositionBackground === enable) return;
|
|
3234
|
+
this.alwaysPostpositionBackground = enable;
|
|
3235
|
+
this.rebuildLyricLines();
|
|
3236
|
+
this.calcLayout();
|
|
3237
|
+
}
|
|
3238
|
+
/** 获取当前是否设置了让背景人声行始终后置显示 */
|
|
3239
|
+
getAlwaysPostpositionBackground() {
|
|
3240
|
+
return this.alwaysPostpositionBackground;
|
|
3241
|
+
}
|
|
3227
3242
|
getElement() {
|
|
3228
3243
|
return this.element;
|
|
3229
3244
|
}
|
|
@@ -3234,6 +3249,191 @@ var LyricPlayerBase = class extends EventTarget {
|
|
|
3234
3249
|
}
|
|
3235
3250
|
};
|
|
3236
3251
|
//#endregion
|
|
3252
|
+
//#region src/lyric-player/base/group.ts
|
|
3253
|
+
var LyricLineGroupBase = class {
|
|
3254
|
+
posY = new Spring(0);
|
|
3255
|
+
bgSlideY = new Spring(-80);
|
|
3256
|
+
top = 0;
|
|
3257
|
+
delay = 0;
|
|
3258
|
+
isActive = false;
|
|
3259
|
+
opacity = 1;
|
|
3260
|
+
blur = 0;
|
|
3261
|
+
isBgFirst = false;
|
|
3262
|
+
constructor(mainLine, bgLine) {
|
|
3263
|
+
this.mainLine = mainLine;
|
|
3264
|
+
this.bgLine = bgLine;
|
|
3265
|
+
}
|
|
3266
|
+
get startTime() {
|
|
3267
|
+
return this.mainLine.getLine().startTime;
|
|
3268
|
+
}
|
|
3269
|
+
get endTime() {
|
|
3270
|
+
return this.mainLine.getLine().endTime;
|
|
3271
|
+
}
|
|
3272
|
+
onLineSizeChange(size) {
|
|
3273
|
+
this.mainLine.onLineSizeChange(size);
|
|
3274
|
+
this.bgLine?.onLineSizeChange(size);
|
|
3275
|
+
}
|
|
3276
|
+
setTransform(top, force, delay, isActive, opacity, blur) {
|
|
3277
|
+
this.top = top;
|
|
3278
|
+
this.delay = delay;
|
|
3279
|
+
this.isActive = isActive;
|
|
3280
|
+
this.opacity = opacity;
|
|
3281
|
+
this.blur = blur;
|
|
3282
|
+
this.setLineTransformations(force, delay);
|
|
3283
|
+
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
3284
|
+
const hiddenSlideY = (this.lyricPlayer.getAlwaysPostpositionBackground() ? false : this.isBgFirst) ? 80 : -80;
|
|
3285
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3286
|
+
const targetBgSlideY = isActive || !isPlaying ? 0 : hiddenSlideY;
|
|
3287
|
+
if (force || !enableSpring) {
|
|
3288
|
+
this.posY.setPosition(top);
|
|
3289
|
+
this.bgSlideY.setPosition(targetBgSlideY);
|
|
3290
|
+
this.renderStyles();
|
|
3291
|
+
} else {
|
|
3292
|
+
this.posY.setTargetPosition(top, delay);
|
|
3293
|
+
this.bgSlideY.setTargetPosition(targetBgSlideY, delay);
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
setLineTransformations(force, delay) {
|
|
3297
|
+
const enableScale = this.lyricPlayer.getEnableScale();
|
|
3298
|
+
const isPlaying = this.lyricPlayer.getIsPlaying();
|
|
3299
|
+
const renderMode = this.isActive ? LyricLineRenderMode.GRADIENT : LyricLineRenderMode.SOLID;
|
|
3300
|
+
const SCALE_ASPECT = enableScale ? 97 : 100;
|
|
3301
|
+
let mainScale = 100;
|
|
3302
|
+
if (!this.isActive && isPlaying) mainScale = SCALE_ASPECT;
|
|
3303
|
+
this.mainLine.setTransform(mainScale, 1, 0, force, delay, renderMode);
|
|
3304
|
+
let bgScale = 100;
|
|
3305
|
+
if (!this.isActive && isPlaying) bgScale = 75;
|
|
3306
|
+
this.bgLine?.setTransform(bgScale, 1, 0, force, delay, renderMode);
|
|
3307
|
+
}
|
|
3308
|
+
update(delta) {
|
|
3309
|
+
if (this.lyricPlayer.getEnableSpring()) {
|
|
3310
|
+
this.posY.update(delta);
|
|
3311
|
+
this.bgSlideY.update(delta);
|
|
3312
|
+
this.renderStyles();
|
|
3313
|
+
}
|
|
3314
|
+
this.mainLine.update(delta);
|
|
3315
|
+
this.bgLine?.update(delta);
|
|
3316
|
+
}
|
|
3317
|
+
rebuildAllLines() {
|
|
3318
|
+
this.mainLine.rebuildElement();
|
|
3319
|
+
this.bgLine?.rebuildElement();
|
|
3320
|
+
}
|
|
3321
|
+
enable(time, shouldPlay) {
|
|
3322
|
+
this.mainLine.enable(time, shouldPlay);
|
|
3323
|
+
this.bgLine?.enable(time, shouldPlay);
|
|
3324
|
+
}
|
|
3325
|
+
disable() {
|
|
3326
|
+
this.mainLine.disable();
|
|
3327
|
+
this.bgLine?.disable();
|
|
3328
|
+
}
|
|
3329
|
+
dispose() {
|
|
3330
|
+
this.mainLine.dispose();
|
|
3331
|
+
this.bgLine?.dispose();
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
//#endregion
|
|
3335
|
+
//#region src/lyric-player/dom/lyric-group.ts
|
|
3336
|
+
var LyricLineGroup = class extends LyricLineGroupBase {
|
|
3337
|
+
element;
|
|
3338
|
+
bgWrapper;
|
|
3339
|
+
lastIsActive;
|
|
3340
|
+
constructor(lyricPlayer, mainLine) {
|
|
3341
|
+
super(mainLine);
|
|
3342
|
+
this.lyricPlayer = lyricPlayer;
|
|
3343
|
+
this.element = document.createElement("div");
|
|
3344
|
+
this.element.className = lyric_player_module_default.lyricLineWrapper;
|
|
3345
|
+
this.element.appendChild(mainLine.getElement());
|
|
3346
|
+
this.posY.setPosition(window.innerHeight * 2);
|
|
3347
|
+
lyricPlayer.resizeObserver.observe(this.element);
|
|
3348
|
+
}
|
|
3349
|
+
get isInSight() {
|
|
3350
|
+
const t = this.posY.getCurrentPosition();
|
|
3351
|
+
let h = this.lyricPlayer.lyricGroupSize?.get(this)?.[1];
|
|
3352
|
+
if (h === void 0 || h === 0) h = this.element.clientHeight || 0;
|
|
3353
|
+
const pb = this.lyricPlayer.size[1];
|
|
3354
|
+
const ov = this.lyricPlayer.getOverscanPx();
|
|
3355
|
+
return !(t > pb + h + ov || t < -h - ov);
|
|
3356
|
+
}
|
|
3357
|
+
show() {
|
|
3358
|
+
if (!this.element.parentElement) {
|
|
3359
|
+
const playerEl = this.lyricPlayer.getElement();
|
|
3360
|
+
const groups = this.lyricPlayer.currentLyricGroups;
|
|
3361
|
+
const myIndex = groups.indexOf(this);
|
|
3362
|
+
let referenceNode = null;
|
|
3363
|
+
if (myIndex !== -1) {
|
|
3364
|
+
for (let i = myIndex + 1; i < groups.length; i++) if (groups[i].element.parentElement === playerEl) {
|
|
3365
|
+
referenceNode = groups[i].element;
|
|
3366
|
+
break;
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
playerEl.insertBefore(this.element, referenceNode);
|
|
3370
|
+
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3371
|
+
}
|
|
3372
|
+
this.mainLine.show();
|
|
3373
|
+
this.bgLine?.show();
|
|
3374
|
+
}
|
|
3375
|
+
hide() {
|
|
3376
|
+
if (this.element.parentElement) {
|
|
3377
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3378
|
+
this.element.remove();
|
|
3379
|
+
this.mainLine.teardownContent();
|
|
3380
|
+
this.bgLine?.teardownContent();
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
update(delta) {
|
|
3384
|
+
if (this.isInSight) this.show();
|
|
3385
|
+
else this.hide();
|
|
3386
|
+
super.update(delta);
|
|
3387
|
+
}
|
|
3388
|
+
addBgLine(bgLine) {
|
|
3389
|
+
if (this.bgLine) this.bgLine.dispose();
|
|
3390
|
+
if (this.bgWrapper) this.bgWrapper.remove();
|
|
3391
|
+
this.bgLine = bgLine;
|
|
3392
|
+
const bgStartTime = bgLine.getLine().words[0]?.startTime ?? bgLine.getLine().startTime;
|
|
3393
|
+
const mainStartTime = this.mainLine.getLine().words[0]?.startTime ?? this.mainLine.getLine().startTime;
|
|
3394
|
+
this.isBgFirst = bgStartTime < mainStartTime;
|
|
3395
|
+
if (this.mainLine.getLine().isDuet) bgLine.getElement().classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3396
|
+
this.bgWrapper = document.createElement("div");
|
|
3397
|
+
this.bgWrapper.className = lyric_player_module_default.bgWrapper;
|
|
3398
|
+
this.bgWrapper.appendChild(bgLine.getElement());
|
|
3399
|
+
if (!this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst) {
|
|
3400
|
+
this.bgWrapper.classList.add(lyric_player_module_default.bgWrapperTop);
|
|
3401
|
+
this.element.insertBefore(this.bgWrapper, this.mainLine.getElement());
|
|
3402
|
+
this.bgSlideY.setPosition(80);
|
|
3403
|
+
} else this.element.appendChild(this.bgWrapper);
|
|
3404
|
+
}
|
|
3405
|
+
renderStyles() {
|
|
3406
|
+
const y = this.posY.getCurrentPosition().toFixed(1);
|
|
3407
|
+
this.element.style.transform = `translateY(${y}px)`;
|
|
3408
|
+
this.element.style.opacity = this.opacity.toString();
|
|
3409
|
+
this.element.style.filter = `blur(${Math.min(5, this.blur)}px)`;
|
|
3410
|
+
if (!this.lyricPlayer.getEnableSpring()) this.element.style.transitionDelay = `${this.delay}ms`;
|
|
3411
|
+
if (this.bgWrapper) {
|
|
3412
|
+
if (this.lastIsActive !== this.isActive) {
|
|
3413
|
+
this.lastIsActive = this.isActive;
|
|
3414
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperActive, this.isActive);
|
|
3415
|
+
}
|
|
3416
|
+
const slideY = this.bgSlideY.getCurrentPosition();
|
|
3417
|
+
const slideYStr = slideY.toFixed(1);
|
|
3418
|
+
const activeProgress = clamp01(1 - Math.abs(slideY) / 80);
|
|
3419
|
+
const scaleStr = (.8 + activeProgress * .2).toFixed(3);
|
|
3420
|
+
this.bgWrapper.style.transform = `translateY(${slideYStr}%) scale(${scaleStr})`;
|
|
3421
|
+
const shouldBgFirst = !this.lyricPlayer.getAlwaysPostpositionBackground() && this.isBgFirst;
|
|
3422
|
+
if (shouldBgFirst) {
|
|
3423
|
+
const currentMarginTop = -(this.bgWrapper.clientHeight || 0) * (1 - activeProgress);
|
|
3424
|
+
this.bgWrapper.style.marginTop = `${currentMarginTop.toFixed(1)}px`;
|
|
3425
|
+
} else this.bgWrapper.style.marginTop = "";
|
|
3426
|
+
const isHidden = slideYStr === (shouldBgFirst ? "80.0" : "-80.0") && !this.isActive;
|
|
3427
|
+
this.bgWrapper.classList.toggle(lyric_player_module_default.bgWrapperHidden, isHidden);
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
dispose() {
|
|
3431
|
+
super.dispose();
|
|
3432
|
+
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3433
|
+
this.element.remove();
|
|
3434
|
+
}
|
|
3435
|
+
};
|
|
3436
|
+
//#endregion
|
|
3237
3437
|
//#region src/utils/is-cjk.ts
|
|
3238
3438
|
const isCJK = (char) => {
|
|
3239
3439
|
return /^[\p{Unified_Ideograph}\u0800-\u9FFC]+$/u.test(char);
|
|
@@ -3250,10 +3450,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3250
3450
|
blur = 0;
|
|
3251
3451
|
opacity = 1;
|
|
3252
3452
|
delay = 0;
|
|
3253
|
-
lineTransforms = {
|
|
3254
|
-
posY: new Spring(0),
|
|
3255
|
-
scale: new Spring(100)
|
|
3256
|
-
};
|
|
3453
|
+
lineTransforms = { scale: new Spring(100) };
|
|
3257
3454
|
/**
|
|
3258
3455
|
* 用于 CJK 词语边界检测的分词器
|
|
3259
3456
|
*/
|
|
@@ -3263,9 +3460,7 @@ var LyricLineBase = class extends EventTarget {
|
|
|
3263
3460
|
* 用于正确处理 emoji、复合字符等
|
|
3264
3461
|
*/
|
|
3265
3462
|
static graphemeSegmenter = typeof Intl !== "undefined" && Intl.Segmenter ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
3266
|
-
|
|
3267
|
-
setTransform(top = this.top, scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3268
|
-
this.top = top;
|
|
3463
|
+
setTransform(scale = this.scale, opacity = this.opacity, blur = this.blur, _force = false, delay = 0, _mode = LyricLineRenderMode.SOLID) {
|
|
3269
3464
|
this.scale = scale;
|
|
3270
3465
|
this.opacity = opacity;
|
|
3271
3466
|
this.blur = blur;
|
|
@@ -3743,12 +3938,9 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3743
3938
|
super();
|
|
3744
3939
|
this.lyricPlayer = lyricPlayer;
|
|
3745
3940
|
this.lyricLine = lyricLine;
|
|
3746
|
-
this._prevParentEl = lyricPlayer.getElement();
|
|
3747
|
-
lyricPlayer.resizeObserver.observe(this.element);
|
|
3748
3941
|
this.element.setAttribute("class", lyric_player_module_default.lyricLine);
|
|
3749
3942
|
if (this.lyricLine.isBG) this.element.classList.add(lyric_player_module_default.lyricBgLine);
|
|
3750
3943
|
if (this.lyricLine.isDuet) this.element.classList.add(lyric_player_module_default.lyricDuetLine);
|
|
3751
|
-
this.lineTransforms.posY.setPosition(window.innerHeight * 2);
|
|
3752
3944
|
this.element.appendChild(document.createElement("div"));
|
|
3753
3945
|
this.element.appendChild(document.createElement("div"));
|
|
3754
3946
|
this.element.appendChild(document.createElement("div"));
|
|
@@ -3880,34 +4072,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
3880
4072
|
getLine() {
|
|
3881
4073
|
return this.lyricLine;
|
|
3882
4074
|
}
|
|
3883
|
-
_prevParentEl;
|
|
3884
4075
|
lastStyle = "";
|
|
3885
4076
|
show() {
|
|
3886
|
-
if (!this.element.parentElement) {
|
|
3887
|
-
this._prevParentEl.appendChild(this.element);
|
|
3888
|
-
this.lyricPlayer.resizeObserver.observe(this.element);
|
|
3889
|
-
}
|
|
3890
4077
|
if (!this.built) {
|
|
3891
4078
|
this.rebuildElement();
|
|
3892
4079
|
this.built = true;
|
|
3893
4080
|
this.updateMaskImageSync();
|
|
3894
4081
|
}
|
|
3895
|
-
this.rebuildStyle();
|
|
3896
|
-
}
|
|
3897
|
-
hide() {
|
|
3898
|
-
if (this.element.parentElement) {
|
|
3899
|
-
this._prevParentEl.removeChild(this.element);
|
|
3900
|
-
this.lyricPlayer.resizeObserver.unobserve(this.element);
|
|
3901
|
-
}
|
|
3902
|
-
if (this.built) {
|
|
3903
|
-
this.disposeElements();
|
|
3904
|
-
this.built = false;
|
|
3905
|
-
}
|
|
3906
4082
|
}
|
|
3907
4083
|
rebuildStyle() {
|
|
3908
4084
|
let style = "";
|
|
3909
|
-
style += `transform:
|
|
3910
|
-
if (!this.lyricPlayer.getEnableSpring()
|
|
4085
|
+
style += `transform: scale(${(this.lineTransforms.scale.getCurrentPosition() / 100).toFixed(4)});`;
|
|
4086
|
+
if (!this.lyricPlayer.getEnableSpring()) style += `transition-delay:${this.delay}ms;`;
|
|
3911
4087
|
style += `filter:blur(${Math.min(5, this.blur)}px);`;
|
|
3912
4088
|
if (style !== this.lastStyle) {
|
|
3913
4089
|
this.lastStyle = style;
|
|
@@ -4350,25 +4526,19 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4350
4526
|
this.element.style.setProperty("--bright-mask-alpha", this.currentBrightAlpha.toFixed(3));
|
|
4351
4527
|
this.element.style.setProperty("--dark-mask-alpha", this.currentDarkAlpha.toFixed(3));
|
|
4352
4528
|
}
|
|
4353
|
-
setTransform(
|
|
4354
|
-
super.setTransform(
|
|
4529
|
+
setTransform(scale = this.scale, opacity = 1, blur = 0, force = false, delay = 0, mode = LyricLineRenderMode.SOLID) {
|
|
4530
|
+
super.setTransform(scale, opacity, blur, force, delay);
|
|
4355
4531
|
this.renderMode = mode;
|
|
4356
|
-
const beforeInSight = this.isInSight;
|
|
4357
4532
|
const enableSpring = this.lyricPlayer.getEnableSpring();
|
|
4358
|
-
this.top =
|
|
4533
|
+
this.top = 0;
|
|
4359
4534
|
this.scale = scale;
|
|
4360
4535
|
this.delay = delay * 1e3 | 0;
|
|
4361
4536
|
const main = this.element.children[0];
|
|
4362
4537
|
main.style.opacity = `${opacity}`;
|
|
4363
4538
|
if (force || !enableSpring) {
|
|
4364
4539
|
this.blur = Math.min(32, blur);
|
|
4365
|
-
this.lineTransforms.posY.setPosition(top);
|
|
4366
4540
|
this.lineTransforms.scale.setPosition(scale);
|
|
4367
|
-
|
|
4368
|
-
const afterInSight = this.isInSight;
|
|
4369
|
-
if (beforeInSight || afterInSight) this.show();
|
|
4370
|
-
else this.hide();
|
|
4371
|
-
} else this.rebuildStyle();
|
|
4541
|
+
this.rebuildStyle();
|
|
4372
4542
|
const currentScale = this.lineTransforms.scale.getCurrentPosition();
|
|
4373
4543
|
this.updateMaskAlphaTargets(currentScale / 100);
|
|
4374
4544
|
this.currentBrightAlpha = this.targetBrightAlpha;
|
|
@@ -4376,21 +4546,18 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4376
4546
|
this.element.style.setProperty("--bright-mask-alpha", String(this.currentBrightAlpha));
|
|
4377
4547
|
this.element.style.setProperty("--dark-mask-alpha", String(this.currentDarkAlpha));
|
|
4378
4548
|
} else {
|
|
4379
|
-
this.lineTransforms.posY.setTargetPosition(top, delay);
|
|
4380
4549
|
this.lineTransforms.scale.setTargetPosition(scale);
|
|
4381
4550
|
if (this.blur !== Math.min(5, blur)) {
|
|
4382
4551
|
this.blur = Math.min(5, blur);
|
|
4383
|
-
|
|
4384
|
-
this.element.style.filter = `blur(${roundedBlur}px)`;
|
|
4552
|
+
this.element.style.filter = `blur(${blur.toFixed(3)}px)`;
|
|
4385
4553
|
}
|
|
4386
4554
|
}
|
|
4387
4555
|
}
|
|
4388
4556
|
update(delta = 0) {
|
|
4389
4557
|
if (!this.lyricPlayer.getEnableSpring()) return;
|
|
4390
|
-
this.lineTransforms.posY.update(delta);
|
|
4391
4558
|
this.lineTransforms.scale.update(delta);
|
|
4392
|
-
|
|
4393
|
-
|
|
4559
|
+
this.rebuildStyle();
|
|
4560
|
+
if (!this.built) return;
|
|
4394
4561
|
const currentScale = this.lineTransforms.scale.getCurrentPosition() / 100;
|
|
4395
4562
|
this.updateMaskAlphaTargets(currentScale);
|
|
4396
4563
|
this.applyAlphaToDom(delta);
|
|
@@ -4398,13 +4565,11 @@ var LyricLineEl = class extends LyricLineBase {
|
|
|
4398
4565
|
_getDebugTargetPos() {
|
|
4399
4566
|
return `[位移: ${this.top}; 缩放: ${this.scale}; 延时: ${this.delay}]`;
|
|
4400
4567
|
}
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
const ov = this.lyricPlayer.getOverscanPx();
|
|
4407
|
-
return !(t > pb + h + ov || b < -h - ov);
|
|
4568
|
+
teardownContent() {
|
|
4569
|
+
if (this.built) {
|
|
4570
|
+
this.disposeElements();
|
|
4571
|
+
this.built = false;
|
|
4572
|
+
}
|
|
4408
4573
|
}
|
|
4409
4574
|
disposeElements() {
|
|
4410
4575
|
this.balancer?.reset();
|
|
@@ -4452,7 +4617,7 @@ var LyricLineMouseEvent = class extends MouseEvent {
|
|
|
4452
4617
|
* 尽可能贴切 Apple Music for iPad 的歌词效果设计,且做了力所能及的优化措施
|
|
4453
4618
|
*/
|
|
4454
4619
|
var DomLyricPlayer = class extends LyricPlayerBase {
|
|
4455
|
-
|
|
4620
|
+
currentLyricGroups = [];
|
|
4456
4621
|
onResize() {
|
|
4457
4622
|
const computedStyles = getComputedStyle(this.element);
|
|
4458
4623
|
this._baseFontSize = Number.parseFloat(computedStyles.fontSize);
|
|
@@ -4489,7 +4654,10 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4489
4654
|
rebuildStyle() {}
|
|
4490
4655
|
setWordFadeWidth(value = .5) {
|
|
4491
4656
|
super.setWordFadeWidth(value);
|
|
4492
|
-
for (const
|
|
4657
|
+
for (const group of this.currentLyricGroups) {
|
|
4658
|
+
group.mainLine.updateMaskImageSync();
|
|
4659
|
+
group.bgLine?.updateMaskImageSync();
|
|
4660
|
+
}
|
|
4493
4661
|
}
|
|
4494
4662
|
/**
|
|
4495
4663
|
* 设置当前播放歌词,要注意传入后这个数组内的信息不得修改,否则会发生错误
|
|
@@ -4501,36 +4669,52 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4501
4669
|
if (this.hasDuetLine) this.element.classList.add(lyric_player_module_default.hasDuetLine);
|
|
4502
4670
|
else this.element.classList.remove(lyric_player_module_default.hasDuetLine);
|
|
4503
4671
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${initialTime}`);
|
|
4504
|
-
for (const
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4672
|
+
for (const group of this.currentLyricGroups) {
|
|
4673
|
+
const linesToDispose = [group.mainLine, group.bgLine].filter((line) => !!line);
|
|
4674
|
+
for (const line of linesToDispose) {
|
|
4675
|
+
line.removeMouseEventListener("click", this.onLineClickedHandler);
|
|
4676
|
+
line.removeMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4677
|
+
}
|
|
4678
|
+
group.dispose();
|
|
4508
4679
|
}
|
|
4509
|
-
this.
|
|
4680
|
+
this.currentLyricGroups = [];
|
|
4681
|
+
let currentGroup = null;
|
|
4682
|
+
for (let i = 0; i < this.processedLines.length; i++) {
|
|
4683
|
+
const line = this.processedLines[i];
|
|
4510
4684
|
const lineEl = new LyricLineEl(this, line);
|
|
4511
4685
|
lineEl.addMouseEventListener("click", this.onLineClickedHandler);
|
|
4512
4686
|
lineEl.addMouseEventListener("contextmenu", this.onLineClickedHandler);
|
|
4513
4687
|
this.lyricLinesIndexes.set(lineEl, i);
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4688
|
+
if (!line.isBG || !currentGroup) {
|
|
4689
|
+
currentGroup = new LyricLineGroup(this, lineEl);
|
|
4690
|
+
this.currentLyricGroups.push(currentGroup);
|
|
4691
|
+
this.lyricGroupElementMap.set(currentGroup.element, currentGroup);
|
|
4692
|
+
} else currentGroup.addBgLine(lineEl);
|
|
4693
|
+
}
|
|
4517
4694
|
this.setLinePosXSpringParams({});
|
|
4518
4695
|
this.setLinePosYSpringParams({});
|
|
4519
4696
|
this.setLineScaleSpringParams({});
|
|
4697
|
+
this.setCurrentTime(initialTime, true);
|
|
4520
4698
|
this.calcLayout(true);
|
|
4521
4699
|
this.update(0);
|
|
4522
4700
|
}
|
|
4523
4701
|
pause() {
|
|
4524
4702
|
super.pause();
|
|
4525
|
-
this.element.classList.remove(
|
|
4703
|
+
this.element.classList.remove(lyric_player_module_default.playing);
|
|
4526
4704
|
this.interludeDots.pause();
|
|
4527
|
-
for (const
|
|
4705
|
+
for (const group of this.currentLyricGroups) {
|
|
4706
|
+
group.mainLine.pause();
|
|
4707
|
+
group.bgLine?.pause();
|
|
4708
|
+
}
|
|
4528
4709
|
}
|
|
4529
4710
|
resume() {
|
|
4530
4711
|
super.resume();
|
|
4531
|
-
this.element.classList.add(
|
|
4712
|
+
this.element.classList.add(lyric_player_module_default.playing);
|
|
4532
4713
|
this.interludeDots.resume();
|
|
4533
|
-
for (const
|
|
4714
|
+
for (const group of this.currentLyricGroups) {
|
|
4715
|
+
group.mainLine.resume();
|
|
4716
|
+
group.bgLine?.resume();
|
|
4717
|
+
}
|
|
4534
4718
|
}
|
|
4535
4719
|
update(delta = 0) {
|
|
4536
4720
|
if (!this.timelineState.initialLayoutFinished) return;
|
|
@@ -4538,12 +4722,12 @@ var DomLyricPlayer = class extends LyricPlayerBase {
|
|
|
4538
4722
|
if (!this.supportMaskImage) this.element.style.setProperty("--amll-player-time", `${this.timelineState.currentTime}`);
|
|
4539
4723
|
if (!this.isPageVisible) return;
|
|
4540
4724
|
const deltaS = delta / 1e3;
|
|
4541
|
-
for (const
|
|
4725
|
+
for (const group of this.currentLyricGroups) group.update(deltaS);
|
|
4542
4726
|
}
|
|
4543
4727
|
dispose() {
|
|
4544
4728
|
super.dispose();
|
|
4545
4729
|
this.element.remove();
|
|
4546
|
-
for (const
|
|
4730
|
+
for (const group of this.currentLyricGroups) group.dispose();
|
|
4547
4731
|
this.bottomLine.dispose();
|
|
4548
4732
|
this.interludeDots.dispose();
|
|
4549
4733
|
}
|