@uimaxbai/am-lyrics 1.3.0 → 1.4.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/README.md +0 -5
- package/dist/src/AmLyrics.d.ts +5 -7
- package/dist/src/AmLyrics.d.ts.map +1 -1
- package/dist/src/am-lyrics.js +473 -352
- package/dist/src/am-lyrics.js.map +1 -1
- package/dist/src/react.js +473 -352
- package/dist/src/react.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/AmLyrics.ts +552 -403
- package/fix.cjs +0 -7
- package/patch.diff +0 -210
- package/patch2.diff +0 -26
package/dist/src/am-lyrics.js
CHANGED
|
@@ -319,7 +319,7 @@ class GoogleService {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
const VERSION = '1.
|
|
322
|
+
const VERSION = '1.4.1';
|
|
323
323
|
const INSTRUMENTAL_THRESHOLD_MS = 7000; // Show dots for gaps >= 7s
|
|
324
324
|
const FETCH_TIMEOUT_MS = 8000; // Timeout for all lyrics fetch requests
|
|
325
325
|
const SEEK_THRESHOLD_MS = 500;
|
|
@@ -342,32 +342,17 @@ function fetchWithTimeout(url, options = {}, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
|
342
342
|
}
|
|
343
343
|
const KPOE_SERVERS = [
|
|
344
344
|
'https://lyricsplus.binimum.org',
|
|
345
|
-
'https://lyricsplus.atomix.one',
|
|
346
345
|
'https://lyricsplus-seven.vercel.app',
|
|
347
346
|
'https://lyricsplus.prjktla.workers.dev',
|
|
348
347
|
'https://lyrics-plus-backend.vercel.app',
|
|
349
348
|
];
|
|
350
349
|
const DEFAULT_KPOE_SOURCE_ORDER = 'apple,lyricsplus,musixmatch,spotify,qq,deezer,musixmatch-word';
|
|
351
|
-
const TIDAL_SERVERS = [
|
|
352
|
-
'https://arran.monochrome.tf',
|
|
353
|
-
'https://api.monochrome.tf/',
|
|
354
|
-
'https://triton.squid.wtf',
|
|
355
|
-
'https://wolf.qqdl.site',
|
|
356
|
-
'https://maus.qqdl.site',
|
|
357
|
-
'https://vogel.qqdl.site',
|
|
358
|
-
'https://katze.qqdl.site',
|
|
359
|
-
'https://hund.qqdl.site',
|
|
360
|
-
'https://tidal.kinoplus.online',
|
|
361
|
-
'https://hifi-one.spotisaver.net',
|
|
362
|
-
'https://hifi-two.spotisaver.net',
|
|
363
|
-
];
|
|
364
350
|
const GENIUS_WORKER_URL = 'https://fetch-genius.samidy.workers.dev/';
|
|
365
351
|
class AmLyrics extends i {
|
|
366
352
|
constructor() {
|
|
367
353
|
super(...arguments);
|
|
368
354
|
this.downloadFormat = 'auto';
|
|
369
355
|
this.highlightColor = '#ffffff';
|
|
370
|
-
this.hoverBackgroundColor = 'rgba(255, 255, 255, 0.13)';
|
|
371
356
|
this.autoScroll = true;
|
|
372
357
|
this.interpolate = true;
|
|
373
358
|
this.showRomanization = false;
|
|
@@ -412,6 +397,10 @@ class AmLyrics extends i {
|
|
|
412
397
|
// Syllable animation tracking
|
|
413
398
|
this.lastActiveIndex = 0;
|
|
414
399
|
this.visibleLineIds = new Set();
|
|
400
|
+
// Cached element tracking to avoid repeated querySelectorAll calls
|
|
401
|
+
this.preActiveLineElements = [];
|
|
402
|
+
this.positionedLineElements = [];
|
|
403
|
+
this.activeGapLineElements = [];
|
|
415
404
|
// Bound handler references for proper event listener removal
|
|
416
405
|
this._boundHandleUserScroll = this.handleUserScroll.bind(this);
|
|
417
406
|
this._boundAnimateProgress = this.animateProgress.bind(this);
|
|
@@ -484,6 +473,31 @@ class AmLyrics extends i {
|
|
|
484
473
|
}
|
|
485
474
|
set currentTime(value) {
|
|
486
475
|
const oldValue = this._currentTime;
|
|
476
|
+
// If the new time is significantly smaller than the old time (e.g. song looped)
|
|
477
|
+
if (value < oldValue && oldValue - value > 1000 && this.lyrics) {
|
|
478
|
+
this.activeLineIndices = [];
|
|
479
|
+
this.activeMainWordIndices.clear();
|
|
480
|
+
this.activeBackgroundWordIndices.clear();
|
|
481
|
+
this.mainWordProgress.clear();
|
|
482
|
+
this.backgroundWordProgress.clear();
|
|
483
|
+
this.mainWordAnimations.clear();
|
|
484
|
+
this.backgroundWordAnimations.clear();
|
|
485
|
+
this.preActiveLineElements = [];
|
|
486
|
+
this.positionedLineElements = [];
|
|
487
|
+
this.activeGapLineElements = [];
|
|
488
|
+
// Stop all running animations and clear highlights immediately
|
|
489
|
+
if (this.lyricsContainer) {
|
|
490
|
+
const activeLines = this.lyricsContainer.querySelectorAll('.lyrics-line.active, .lyrics-line.pre-active');
|
|
491
|
+
activeLines.forEach(line => {
|
|
492
|
+
line.classList.remove('active', 'pre-active');
|
|
493
|
+
AmLyrics.resetSyllables(line);
|
|
494
|
+
});
|
|
495
|
+
const activeGaps = this.lyricsContainer.querySelectorAll('.lyrics-gap.active, .lyrics-gap.gap-exiting');
|
|
496
|
+
activeGaps.forEach(gap => gap.classList.remove('active', 'gap-exiting'));
|
|
497
|
+
// Reset gap cache since we manually messed with the elements
|
|
498
|
+
this.gapElementCache.clear();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
487
501
|
this._currentTime = value;
|
|
488
502
|
if (oldValue !== value && this.lyrics) {
|
|
489
503
|
this._onTimeChanged(oldValue, value);
|
|
@@ -545,6 +559,9 @@ class AmLyrics extends i {
|
|
|
545
559
|
this.lyricsContainer.removeEventListener('wheel', this._boundHandleUserScroll);
|
|
546
560
|
this.lyricsContainer.removeEventListener('touchmove', this._boundHandleUserScroll);
|
|
547
561
|
}
|
|
562
|
+
this.preActiveLineElements = [];
|
|
563
|
+
this.positionedLineElements = [];
|
|
564
|
+
this.activeGapLineElements = [];
|
|
548
565
|
}
|
|
549
566
|
async fetchLyrics() {
|
|
550
567
|
// Cancel any in-flight fetch to prevent stale results from racing
|
|
@@ -579,16 +596,7 @@ class AmLyrics extends i {
|
|
|
579
596
|
}
|
|
580
597
|
}
|
|
581
598
|
if (collectedSources.length === 0 && resolvedMetadata?.metadata) {
|
|
582
|
-
|
|
583
|
-
if (tidalResult && tidalResult.lines.length > 0) {
|
|
584
|
-
collectedSources.push({
|
|
585
|
-
lines: tidalResult.lines,
|
|
586
|
-
source: 'Tidal',
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
// Fallback: LRCLIB
|
|
591
|
-
if (collectedSources.length === 0 && resolvedMetadata?.metadata) {
|
|
599
|
+
// Fallback: LRCLIB
|
|
592
600
|
const lrclibResult = await AmLyrics.fetchLyricsFromLrclib(resolvedMetadata.metadata);
|
|
593
601
|
if (lrclibResult && lrclibResult.lines.length > 0) {
|
|
594
602
|
collectedSources.push({
|
|
@@ -608,15 +616,17 @@ class AmLyrics extends i {
|
|
|
608
616
|
}
|
|
609
617
|
this.hasFetchedAllProviders =
|
|
610
618
|
collectedSources.length === 0 ||
|
|
611
|
-
collectedSources.some(s => s.source === 'LRCLIB' ||
|
|
612
|
-
s.source === 'Tidal' ||
|
|
613
|
-
s.source === 'Genius');
|
|
619
|
+
collectedSources.some(s => s.source === 'LRCLIB' || s.source === 'Genius');
|
|
614
620
|
this._updateFooter();
|
|
615
621
|
if (collectedSources.length > 0) {
|
|
616
622
|
this.availableSources = AmLyrics.mergeAndSortSources(collectedSources);
|
|
617
623
|
this.currentSourceIndex = 0;
|
|
618
|
-
|
|
619
|
-
this.
|
|
624
|
+
const sourceResult = this.availableSources[0];
|
|
625
|
+
this.lyrics = sourceResult.lines;
|
|
626
|
+
this.lyricsSource = sourceResult.source;
|
|
627
|
+
if (sourceResult.songwriters) {
|
|
628
|
+
this.songwriters = sourceResult.songwriters;
|
|
629
|
+
}
|
|
620
630
|
await this.onLyricsLoaded();
|
|
621
631
|
return;
|
|
622
632
|
}
|
|
@@ -638,6 +648,9 @@ class AmLyrics extends i {
|
|
|
638
648
|
this.backgroundWordProgress.clear();
|
|
639
649
|
this.mainWordAnimations.clear();
|
|
640
650
|
this.backgroundWordAnimations.clear();
|
|
651
|
+
this.preActiveLineElements = [];
|
|
652
|
+
this.positionedLineElements = [];
|
|
653
|
+
this.activeGapLineElements = [];
|
|
641
654
|
if (this.lyricsContainer) {
|
|
642
655
|
this.isProgrammaticScroll = true;
|
|
643
656
|
this.lyricsContainer.scrollTop = 0;
|
|
@@ -667,36 +680,30 @@ class AmLyrics extends i {
|
|
|
667
680
|
return 2;
|
|
668
681
|
if (lower.includes('musixmatch') && hasWordSync)
|
|
669
682
|
return 3;
|
|
670
|
-
if (lower.includes('tidal') && hasWordSync)
|
|
671
|
-
return 4;
|
|
672
683
|
if (lower.includes('lrclib') && hasWordSync)
|
|
673
|
-
return
|
|
684
|
+
return 4;
|
|
674
685
|
if (hasWordSync)
|
|
675
|
-
return
|
|
686
|
+
return 5;
|
|
676
687
|
if (lower.includes('apple') && !hasWordSync && !isUnsynced)
|
|
677
|
-
return
|
|
688
|
+
return 6;
|
|
678
689
|
if (isQQ && !hasWordSync && !isUnsynced)
|
|
679
|
-
return
|
|
690
|
+
return 7;
|
|
680
691
|
if (lower.includes('musixmatch') && !hasWordSync && !isUnsynced)
|
|
681
|
-
return
|
|
682
|
-
if (lower.includes('tidal') && !hasWordSync && !isUnsynced)
|
|
683
|
-
return 10;
|
|
692
|
+
return 8;
|
|
684
693
|
if (lower.includes('lrclib') && !hasWordSync && !isUnsynced)
|
|
685
|
-
return
|
|
694
|
+
return 9;
|
|
686
695
|
if (!hasWordSync && !isUnsynced)
|
|
687
|
-
return
|
|
696
|
+
return 10;
|
|
688
697
|
if (lower.includes('apple') && isUnsynced)
|
|
689
|
-
return
|
|
698
|
+
return 11;
|
|
690
699
|
if (isQQ && isUnsynced)
|
|
691
|
-
return
|
|
700
|
+
return 12;
|
|
692
701
|
if (lower.includes('musixmatch') && isUnsynced)
|
|
693
|
-
return
|
|
694
|
-
if (lower.includes('tidal') && isUnsynced)
|
|
695
|
-
return 16;
|
|
702
|
+
return 13;
|
|
696
703
|
if (lower.includes('lrclib') && isUnsynced)
|
|
697
|
-
return
|
|
704
|
+
return 14;
|
|
698
705
|
if (lower.includes('genius'))
|
|
699
|
-
return
|
|
706
|
+
return 15;
|
|
700
707
|
return 20;
|
|
701
708
|
}
|
|
702
709
|
static mergeAndSortSources(collectedSources) {
|
|
@@ -727,13 +734,6 @@ class AmLyrics extends i {
|
|
|
727
734
|
const resolvedMetadata = await this.resolveSongMetadata();
|
|
728
735
|
if (resolvedMetadata?.metadata) {
|
|
729
736
|
const newSources = [];
|
|
730
|
-
// Try Tidal if not fetched
|
|
731
|
-
if (!this.availableSources.some(s => s.source.toLowerCase().includes('tidal'))) {
|
|
732
|
-
const tidalResult = await AmLyrics.fetchLyricsFromTidal(resolvedMetadata.metadata, resolvedMetadata.catalogIsrc);
|
|
733
|
-
if (tidalResult && tidalResult.lines.length > 0) {
|
|
734
|
-
newSources.push({ lines: tidalResult.lines, source: 'Tidal' });
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
737
|
// Try LRCLIB if not fetched
|
|
738
738
|
if (!this.availableSources.some(s => s.source.toLowerCase().includes('lrclib'))) {
|
|
739
739
|
const lrclibResult = await AmLyrics.fetchLyricsFromLrclib(resolvedMetadata.metadata);
|
|
@@ -768,8 +768,12 @@ class AmLyrics extends i {
|
|
|
768
768
|
if (this.availableSources.length > 1) {
|
|
769
769
|
this.currentSourceIndex =
|
|
770
770
|
(this.currentSourceIndex + 1) % this.availableSources.length;
|
|
771
|
-
|
|
772
|
-
this.
|
|
771
|
+
const sourceResult = this.availableSources[this.currentSourceIndex];
|
|
772
|
+
this.lyrics = sourceResult.lines;
|
|
773
|
+
this.lyricsSource = sourceResult.source;
|
|
774
|
+
if (sourceResult.songwriters) {
|
|
775
|
+
this.songwriters = sourceResult.songwriters;
|
|
776
|
+
}
|
|
773
777
|
await this.onLyricsLoaded();
|
|
774
778
|
}
|
|
775
779
|
}
|
|
@@ -778,6 +782,7 @@ class AmLyrics extends i {
|
|
|
778
782
|
title: this.songTitle?.trim() ?? '',
|
|
779
783
|
artist: this.songArtist?.trim() ?? '',
|
|
780
784
|
album: this.songAlbum?.trim() || undefined,
|
|
785
|
+
songwriters: this.songwriters?.trim() || undefined,
|
|
781
786
|
durationMs: undefined,
|
|
782
787
|
};
|
|
783
788
|
if (typeof this.songDurationMs === 'number' && this.songDurationMs > 0) {
|
|
@@ -817,6 +822,9 @@ class AmLyrics extends i {
|
|
|
817
822
|
if (!metadata.album && catalogResult.album) {
|
|
818
823
|
metadata.album = catalogResult.album;
|
|
819
824
|
}
|
|
825
|
+
if (!metadata.songwriters && catalogResult.songwriters) {
|
|
826
|
+
metadata.songwriters = catalogResult.songwriters;
|
|
827
|
+
}
|
|
820
828
|
if (metadata.durationMs == null &&
|
|
821
829
|
typeof catalogResult.durationMs === 'number' &&
|
|
822
830
|
catalogResult.durationMs > 0) {
|
|
@@ -1007,9 +1015,13 @@ class AmLyrics extends i {
|
|
|
1007
1015
|
const ttmlRes = await fetchWithTimeout(result.lyricsUrl);
|
|
1008
1016
|
if (ttmlRes.ok) {
|
|
1009
1017
|
const ttmlText = await ttmlRes.text();
|
|
1010
|
-
const
|
|
1011
|
-
if (
|
|
1012
|
-
allResults.push({
|
|
1018
|
+
const parseResult = AmLyrics.parseTTML(ttmlText);
|
|
1019
|
+
if (parseResult && parseResult.lines.length > 0) {
|
|
1020
|
+
allResults.push({
|
|
1021
|
+
lines: parseResult.lines,
|
|
1022
|
+
source: 'BiniLyrics',
|
|
1023
|
+
songwriters: parseResult.songwriters,
|
|
1024
|
+
});
|
|
1013
1025
|
return allResults;
|
|
1014
1026
|
}
|
|
1015
1027
|
}
|
|
@@ -1041,11 +1053,12 @@ class AmLyrics extends i {
|
|
|
1041
1053
|
const ttmlRes = await fetchWithTimeout(result.lyricsUrl);
|
|
1042
1054
|
if (ttmlRes.ok) {
|
|
1043
1055
|
const ttmlText = await ttmlRes.text();
|
|
1044
|
-
const
|
|
1045
|
-
if (
|
|
1056
|
+
const parseResult = AmLyrics.parseTTML(ttmlText);
|
|
1057
|
+
if (parseResult && parseResult.lines.length > 0) {
|
|
1046
1058
|
allResults.push({
|
|
1047
|
-
lines,
|
|
1059
|
+
lines: parseResult.lines,
|
|
1048
1060
|
source: 'BiniLyrics',
|
|
1061
|
+
songwriters: parseResult.songwriters,
|
|
1049
1062
|
});
|
|
1050
1063
|
return allResults;
|
|
1051
1064
|
}
|
|
@@ -1178,77 +1191,6 @@ class AmLyrics extends i {
|
|
|
1178
1191
|
}
|
|
1179
1192
|
return lines;
|
|
1180
1193
|
}
|
|
1181
|
-
/**
|
|
1182
|
-
* Fetch lyrics from Tidal API.
|
|
1183
|
-
* Picks 2 random servers, tries search + lyrics on each.
|
|
1184
|
-
*/
|
|
1185
|
-
static async fetchLyricsFromTidal(metadata, isrc) {
|
|
1186
|
-
const title = metadata.title?.trim();
|
|
1187
|
-
const artist = metadata.artist?.trim();
|
|
1188
|
-
if (!title || !artist)
|
|
1189
|
-
return null;
|
|
1190
|
-
// Pick 3 random unique servers for better reliability
|
|
1191
|
-
const shuffled = [...TIDAL_SERVERS].sort(() => Math.random() - 0.5);
|
|
1192
|
-
const serversToTry = shuffled.slice(0, 3);
|
|
1193
|
-
for (const base of serversToTry) {
|
|
1194
|
-
try {
|
|
1195
|
-
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
|
|
1196
|
-
// Step 1: Search for the track
|
|
1197
|
-
const searchQuery = `${title} ${artist}`;
|
|
1198
|
-
const searchParams = new URLSearchParams({ s: searchQuery });
|
|
1199
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1200
|
-
const searchResponse = await fetchWithTimeout(`${normalizedBase}/search/?${searchParams.toString()}`);
|
|
1201
|
-
if (!searchResponse.ok) {
|
|
1202
|
-
// eslint-disable-next-line no-continue
|
|
1203
|
-
continue;
|
|
1204
|
-
}
|
|
1205
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1206
|
-
const searchData = await searchResponse.json();
|
|
1207
|
-
const items = searchData?.data?.items;
|
|
1208
|
-
if (!Array.isArray(items) || items.length === 0) {
|
|
1209
|
-
// eslint-disable-next-line no-continue
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
// Find best match: prefer ISRC match, then first result
|
|
1213
|
-
let bestTrack = items[0];
|
|
1214
|
-
if (isrc) {
|
|
1215
|
-
const isrcMatch = items.find((item) => item.isrc && item.isrc.toLowerCase() === isrc.toLowerCase());
|
|
1216
|
-
if (isrcMatch) {
|
|
1217
|
-
bestTrack = isrcMatch;
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
const trackId = bestTrack?.id;
|
|
1221
|
-
if (!trackId) {
|
|
1222
|
-
// eslint-disable-next-line no-continue
|
|
1223
|
-
continue;
|
|
1224
|
-
}
|
|
1225
|
-
// Step 2: Fetch lyrics
|
|
1226
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1227
|
-
const lyricsResponse = await fetchWithTimeout(`${normalizedBase}/lyrics/?id=${trackId}`);
|
|
1228
|
-
if (!lyricsResponse.ok) {
|
|
1229
|
-
// eslint-disable-next-line no-continue
|
|
1230
|
-
continue;
|
|
1231
|
-
}
|
|
1232
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1233
|
-
const lyricsData = await lyricsResponse.json();
|
|
1234
|
-
const subtitles = lyricsData?.lyrics?.subtitles;
|
|
1235
|
-
if (subtitles && typeof subtitles === 'string') {
|
|
1236
|
-
const lines = AmLyrics.parseLrcSubtitles(subtitles);
|
|
1237
|
-
if (lines.length > 0) {
|
|
1238
|
-
const provider = lyricsData?.lyrics?.lyricsProvider || 'Tidal';
|
|
1239
|
-
return {
|
|
1240
|
-
lines,
|
|
1241
|
-
source: `Tidal (${provider})`,
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
catch {
|
|
1247
|
-
// Try next server
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
return null;
|
|
1251
|
-
}
|
|
1252
1194
|
/**
|
|
1253
1195
|
* Fetch lyrics from LRCLIB.
|
|
1254
1196
|
* Uses search endpoint, prefers synced lyrics.
|
|
@@ -1431,6 +1373,19 @@ class AmLyrics extends i {
|
|
|
1431
1373
|
agentMap[id] = type;
|
|
1432
1374
|
}
|
|
1433
1375
|
}
|
|
1376
|
+
let songwriters;
|
|
1377
|
+
const songwritersNodes = doc.getElementsByTagName('songwriter');
|
|
1378
|
+
if (songwritersNodes.length > 0) {
|
|
1379
|
+
const names = [];
|
|
1380
|
+
for (let i = 0; i < songwritersNodes.length; i += 1) {
|
|
1381
|
+
if (songwritersNodes[i].textContent) {
|
|
1382
|
+
names.push(songwritersNodes[i].textContent);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
if (names.length > 0) {
|
|
1386
|
+
songwriters = names.join(', ');
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1434
1389
|
const translationNodes = doc.getElementsByTagName('translation');
|
|
1435
1390
|
for (let i = 0; i < translationNodes.length; i += 1) {
|
|
1436
1391
|
const texts = translationNodes[i].getElementsByTagName('text');
|
|
@@ -1547,7 +1502,7 @@ class AmLyrics extends i {
|
|
|
1547
1502
|
text: bgText,
|
|
1548
1503
|
timestamp: timeToMs(bgSpan.getAttribute('begin')),
|
|
1549
1504
|
endtime: timeToMs(bgSpan.getAttribute('end')),
|
|
1550
|
-
part:
|
|
1505
|
+
part: !/\s$/.test(bgText),
|
|
1551
1506
|
});
|
|
1552
1507
|
}
|
|
1553
1508
|
// eslint-disable-next-line no-continue
|
|
@@ -1570,7 +1525,7 @@ class AmLyrics extends i {
|
|
|
1570
1525
|
text,
|
|
1571
1526
|
timestamp: timeToMs(span.getAttribute('begin')),
|
|
1572
1527
|
endtime: timeToMs(span.getAttribute('end')),
|
|
1573
|
-
part:
|
|
1528
|
+
part: !/\s$/.test(text),
|
|
1574
1529
|
});
|
|
1575
1530
|
}
|
|
1576
1531
|
}
|
|
@@ -1656,7 +1611,7 @@ class AmLyrics extends i {
|
|
|
1656
1611
|
oppositeTurn: alignment === 'end',
|
|
1657
1612
|
});
|
|
1658
1613
|
}
|
|
1659
|
-
return lines;
|
|
1614
|
+
return { lines, songwriters };
|
|
1660
1615
|
}
|
|
1661
1616
|
catch (e) {
|
|
1662
1617
|
// eslint-disable-next-line no-console
|
|
@@ -1821,7 +1776,10 @@ class AmLyrics extends i {
|
|
|
1821
1776
|
if (!newActiveLines.includes(lineIndex)) {
|
|
1822
1777
|
const lineElement = this._getLineElement(lineIndex);
|
|
1823
1778
|
if (lineElement) {
|
|
1824
|
-
lineElement.classList.remove('active');
|
|
1779
|
+
lineElement.classList.remove('active', 'pre-active');
|
|
1780
|
+
const preIdx = this.preActiveLineElements.indexOf(lineElement);
|
|
1781
|
+
if (preIdx !== -1)
|
|
1782
|
+
this.preActiveLineElements.splice(preIdx, 1);
|
|
1825
1783
|
AmLyrics.resetSyllables(lineElement);
|
|
1826
1784
|
}
|
|
1827
1785
|
}
|
|
@@ -1833,6 +1791,9 @@ class AmLyrics extends i {
|
|
|
1833
1791
|
if (lineElement) {
|
|
1834
1792
|
lineElement.classList.add('active');
|
|
1835
1793
|
lineElement.classList.remove('pre-active');
|
|
1794
|
+
const preIdx = this.preActiveLineElements.indexOf(lineElement);
|
|
1795
|
+
if (preIdx !== -1)
|
|
1796
|
+
this.preActiveLineElements.splice(preIdx, 1);
|
|
1836
1797
|
}
|
|
1837
1798
|
}
|
|
1838
1799
|
}
|
|
@@ -1852,10 +1813,9 @@ class AmLyrics extends i {
|
|
|
1852
1813
|
}
|
|
1853
1814
|
}
|
|
1854
1815
|
// Also update syllables in active gap lines (breathing dots)
|
|
1855
|
-
const
|
|
1856
|
-
activeGaps.forEach(gapLine => {
|
|
1816
|
+
for (const gapLine of this.activeGapLineElements) {
|
|
1857
1817
|
AmLyrics.updateSyllablesForLine(gapLine, newTime);
|
|
1858
|
-
}
|
|
1818
|
+
}
|
|
1859
1819
|
// Imperatively manage gap active state
|
|
1860
1820
|
if (this.gapElementCache.size > 0) {
|
|
1861
1821
|
for (const [, gap] of this.gapElementCache) {
|
|
@@ -1866,9 +1826,21 @@ class AmLyrics extends i {
|
|
|
1866
1826
|
const isExiting = gap.classList.contains('gap-exiting');
|
|
1867
1827
|
const exitLeadMs = GAP_EXIT_LEAD_MS;
|
|
1868
1828
|
const shouldStartExiting = isActive && !isExiting && newTime >= gapEndTime - exitLeadMs;
|
|
1869
|
-
if (shouldBeActive && !isActive && !isExiting) {
|
|
1829
|
+
if (shouldBeActive && (!isActive || isSeek) && !isExiting) {
|
|
1870
1830
|
gap.classList.remove('gap-exiting');
|
|
1831
|
+
if (isSeek && isActive) {
|
|
1832
|
+
gap.classList.remove('active');
|
|
1833
|
+
// eslint-disable-next-line no-void
|
|
1834
|
+
void gap.offsetWidth; // Force reflow
|
|
1835
|
+
}
|
|
1836
|
+
const gapDuration = gapEndTime - gapStartTime;
|
|
1837
|
+
const baseLoopDelay = AmLyrics.getGapLoopDelay(gapDuration);
|
|
1838
|
+
const totalDelay = baseLoopDelay + (newTime - gapStartTime);
|
|
1839
|
+
gap.style.setProperty('--gap-loop-delay', `-${totalDelay}ms`);
|
|
1871
1840
|
gap.classList.add('active');
|
|
1841
|
+
if (!this.activeGapLineElements.includes(gap)) {
|
|
1842
|
+
this.activeGapLineElements.push(gap);
|
|
1843
|
+
}
|
|
1872
1844
|
const dotSyllables = gap.querySelectorAll('.lyrics-syllable');
|
|
1873
1845
|
dotSyllables.forEach(dot => {
|
|
1874
1846
|
const dotStart = parseFloat(dot.getAttribute('data-start-time') || '0');
|
|
@@ -1876,24 +1848,34 @@ class AmLyrics extends i {
|
|
|
1876
1848
|
if (newTime > dotEnd) {
|
|
1877
1849
|
dot.classList.add('finished');
|
|
1878
1850
|
if (!dot.classList.contains('highlight')) {
|
|
1879
|
-
AmLyrics.updateSyllableAnimation(dot);
|
|
1851
|
+
AmLyrics.updateSyllableAnimation(dot, newTime - dotStart);
|
|
1880
1852
|
}
|
|
1881
1853
|
}
|
|
1882
1854
|
else if (newTime >= dotStart && newTime <= dotEnd) {
|
|
1883
|
-
AmLyrics.updateSyllableAnimation(dot);
|
|
1855
|
+
AmLyrics.updateSyllableAnimation(dot, newTime - dotStart);
|
|
1884
1856
|
}
|
|
1885
1857
|
});
|
|
1886
1858
|
}
|
|
1887
1859
|
else if (shouldStartExiting) {
|
|
1888
|
-
gap
|
|
1860
|
+
// Cancel gap-loop first, force reflow, then start gap-ended
|
|
1861
|
+
// so the browser sees a clean animation swap
|
|
1889
1862
|
gap.classList.remove('active');
|
|
1863
|
+
// eslint-disable-next-line no-void
|
|
1864
|
+
void gap.offsetWidth;
|
|
1865
|
+
gap.classList.add('gap-exiting');
|
|
1866
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1867
|
+
if (gapIdx !== -1)
|
|
1868
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1890
1869
|
setTimeout(() => {
|
|
1891
1870
|
gap.classList.remove('gap-exiting');
|
|
1892
1871
|
}, GAP_EXIT_LEAD_MS);
|
|
1893
1872
|
}
|
|
1894
|
-
else if (
|
|
1873
|
+
else if (!shouldBeActive && (isActive || isExiting)) {
|
|
1895
1874
|
gap.classList.remove('active');
|
|
1896
1875
|
gap.classList.remove('gap-exiting');
|
|
1876
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1877
|
+
if (gapIdx !== -1)
|
|
1878
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1897
1879
|
}
|
|
1898
1880
|
else if (isExiting && newTime < gapEndTime - exitLeadMs) {
|
|
1899
1881
|
gap.classList.remove('gap-exiting');
|
|
@@ -1911,20 +1893,41 @@ class AmLyrics extends i {
|
|
|
1911
1893
|
const isExiting = gap.classList.contains('gap-exiting');
|
|
1912
1894
|
const exitLeadMs = GAP_EXIT_LEAD_MS;
|
|
1913
1895
|
const shouldStartExiting = isActive && !isExiting && newTime >= gapEndTime - exitLeadMs;
|
|
1914
|
-
if (shouldBeActive && !isActive && !isExiting) {
|
|
1896
|
+
if (shouldBeActive && (!isActive || isSeek) && !isExiting) {
|
|
1915
1897
|
gap.classList.remove('gap-exiting');
|
|
1898
|
+
if (isSeek && isActive) {
|
|
1899
|
+
gap.classList.remove('active');
|
|
1900
|
+
// eslint-disable-next-line no-void
|
|
1901
|
+
void gap.offsetWidth; // Force reflow
|
|
1902
|
+
}
|
|
1903
|
+
const gapDuration = gapEndTime - gapStartTime;
|
|
1904
|
+
const baseLoopDelay = AmLyrics.getGapLoopDelay(gapDuration);
|
|
1905
|
+
const totalDelay = baseLoopDelay + (newTime - gapStartTime);
|
|
1906
|
+
gap.style.setProperty('--gap-loop-delay', `-${totalDelay}ms`);
|
|
1916
1907
|
gap.classList.add('active');
|
|
1908
|
+
if (!this.activeGapLineElements.includes(gap)) {
|
|
1909
|
+
this.activeGapLineElements.push(gap);
|
|
1910
|
+
}
|
|
1917
1911
|
}
|
|
1918
1912
|
else if (shouldStartExiting) {
|
|
1919
|
-
gap
|
|
1913
|
+
// Cancel gap-loop first, force reflow, then start gap-ended
|
|
1920
1914
|
gap.classList.remove('active');
|
|
1915
|
+
// eslint-disable-next-line no-void
|
|
1916
|
+
void gap.offsetWidth;
|
|
1917
|
+
gap.classList.add('gap-exiting');
|
|
1918
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1919
|
+
if (gapIdx !== -1)
|
|
1920
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1921
1921
|
setTimeout(() => {
|
|
1922
1922
|
gap.classList.remove('gap-exiting');
|
|
1923
1923
|
}, GAP_EXIT_LEAD_MS);
|
|
1924
1924
|
}
|
|
1925
|
-
else if (
|
|
1925
|
+
else if (!shouldBeActive && (isActive || isExiting)) {
|
|
1926
1926
|
gap.classList.remove('active');
|
|
1927
1927
|
gap.classList.remove('gap-exiting');
|
|
1928
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1929
|
+
if (gapIdx !== -1)
|
|
1930
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1928
1931
|
}
|
|
1929
1932
|
else if (isExiting && newTime < gapEndTime - exitLeadMs) {
|
|
1930
1933
|
gap.classList.remove('gap-exiting');
|
|
@@ -1939,6 +1942,25 @@ class AmLyrics extends i {
|
|
|
1939
1942
|
else if (this.lastInstrumentalIndex !== null) {
|
|
1940
1943
|
this.lastInstrumentalIndex = null;
|
|
1941
1944
|
}
|
|
1945
|
+
// Check footer active state
|
|
1946
|
+
const lastLyric = this.lyrics && this.lyrics.length > 0
|
|
1947
|
+
? this.lyrics[this.lyrics.length - 1]
|
|
1948
|
+
: null;
|
|
1949
|
+
const footer = this.lyricsContainer.querySelector('.lyrics-footer');
|
|
1950
|
+
if (footer && lastLyric && lastLyric.endtime > 0) {
|
|
1951
|
+
const isFooterActive = newTime > lastLyric.endtime + 200; // Snappier 200ms buffer
|
|
1952
|
+
if (isFooterActive && !footer.classList.contains('active')) {
|
|
1953
|
+
footer.classList.add('active');
|
|
1954
|
+
if (this.autoScroll &&
|
|
1955
|
+
!this.isUserScrolling &&
|
|
1956
|
+
!this.isClickSeeking) {
|
|
1957
|
+
this.focusLine(footer);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
else if (!isFooterActive && footer.classList.contains('active')) {
|
|
1961
|
+
footer.classList.remove('active');
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1942
1964
|
// Pre-scroll: scroll to upcoming line ~0.5s before it starts
|
|
1943
1965
|
if (this.autoScroll &&
|
|
1944
1966
|
!this.isUserScrolling &&
|
|
@@ -1961,6 +1983,9 @@ class AmLyrics extends i {
|
|
|
1961
1983
|
preActiveLineIndex = i;
|
|
1962
1984
|
if (!isBackToBack) {
|
|
1963
1985
|
nextLineEl.classList.add('pre-active');
|
|
1986
|
+
if (!this.preActiveLineElements.includes(nextLineEl)) {
|
|
1987
|
+
this.preActiveLineElements.push(nextLineEl);
|
|
1988
|
+
}
|
|
1964
1989
|
}
|
|
1965
1990
|
this.clearPreActiveClasses(i);
|
|
1966
1991
|
const slowScrollDuration = Math.max(SCROLL_ANIMATION_DURATION_MS, timeUntilStart);
|
|
@@ -1990,6 +2015,9 @@ class AmLyrics extends i {
|
|
|
1990
2015
|
if (lineEl)
|
|
1991
2016
|
lineEl.classList.add('active');
|
|
1992
2017
|
}
|
|
2018
|
+
// Trigger a faux time-change so that updateSyllablesForLine fires
|
|
2019
|
+
// to setup inline syllable CSS wipe animations for whatever the current time is
|
|
2020
|
+
this._onTimeChanged(0, this.currentTime);
|
|
1993
2021
|
}
|
|
1994
2022
|
}
|
|
1995
2023
|
// Handle duration reset (-1 stops playback and resets currentTime to 0)
|
|
@@ -2002,6 +2030,9 @@ class AmLyrics extends i {
|
|
|
2002
2030
|
this.backgroundWordProgress.clear();
|
|
2003
2031
|
this.mainWordAnimations.clear();
|
|
2004
2032
|
this.backgroundWordAnimations.clear();
|
|
2033
|
+
this.preActiveLineElements = [];
|
|
2034
|
+
this.positionedLineElements = [];
|
|
2035
|
+
this.activeGapLineElements = [];
|
|
2005
2036
|
this.setUserScrolling(false);
|
|
2006
2037
|
// Cancel any running animations
|
|
2007
2038
|
if (this.animationFrameId) {
|
|
@@ -2055,7 +2086,7 @@ class AmLyrics extends i {
|
|
|
2055
2086
|
const gap = this.lyrics[targetLineIndex].timestamp -
|
|
2056
2087
|
this.lyrics[prevPrimaryIndex].endtime;
|
|
2057
2088
|
if (gap > 200) {
|
|
2058
|
-
scrollDuration = Math.min(Math.max(gap * 0.
|
|
2089
|
+
scrollDuration = Math.min(Math.max(gap * 0.85, SCROLL_ANIMATION_DURATION_MS), 4000);
|
|
2059
2090
|
}
|
|
2060
2091
|
}
|
|
2061
2092
|
this.focusLine(targetLine, forceScroll, scrollDuration);
|
|
@@ -2117,6 +2148,9 @@ class AmLyrics extends i {
|
|
|
2117
2148
|
this.cachedLineData = null;
|
|
2118
2149
|
this.lineElementCache.clear();
|
|
2119
2150
|
this.gapElementCache.clear();
|
|
2151
|
+
this.preActiveLineElements = [];
|
|
2152
|
+
this.positionedLineElements = [];
|
|
2153
|
+
this.activeGapLineElements = [];
|
|
2120
2154
|
}
|
|
2121
2155
|
_updateCachedIsUnsynced() {
|
|
2122
2156
|
this.cachedIsUnsynced =
|
|
@@ -2129,13 +2163,23 @@ class AmLyrics extends i {
|
|
|
2129
2163
|
return;
|
|
2130
2164
|
this.cachedLineData = this.lyrics.map(line => {
|
|
2131
2165
|
const wordGroups = [];
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2166
|
+
let currentGroupBuffer = [];
|
|
2167
|
+
line.text.forEach((syllable, idx) => {
|
|
2168
|
+
currentGroupBuffer.push(syllable);
|
|
2169
|
+
const nextSyllable = line.text[idx + 1];
|
|
2170
|
+
const endsWithDelimiter = !nextSyllable ||
|
|
2171
|
+
syllable.part === false ||
|
|
2172
|
+
/\s$/.test(syllable.text) ||
|
|
2173
|
+
(nextSyllable &&
|
|
2174
|
+
syllable.isBackground !==
|
|
2175
|
+
nextSyllable.isBackground);
|
|
2176
|
+
if (endsWithDelimiter) {
|
|
2177
|
+
wordGroups.push(currentGroupBuffer);
|
|
2178
|
+
currentGroupBuffer = [];
|
|
2138
2179
|
}
|
|
2180
|
+
});
|
|
2181
|
+
if (currentGroupBuffer.length > 0) {
|
|
2182
|
+
wordGroups.push(currentGroupBuffer);
|
|
2139
2183
|
}
|
|
2140
2184
|
const groupGrowable = new Array(wordGroups.length).fill(false);
|
|
2141
2185
|
const groupGlowing = new Array(wordGroups.length).fill(false);
|
|
@@ -2144,6 +2188,7 @@ class AmLyrics extends i {
|
|
|
2144
2188
|
const vwCharOffset = new Array(wordGroups.length).fill(0);
|
|
2145
2189
|
const vwStartMs = new Array(wordGroups.length).fill(0);
|
|
2146
2190
|
const vwEndMs = new Array(wordGroups.length).fill(0);
|
|
2191
|
+
let lineIsRTL = false;
|
|
2147
2192
|
let vwStart = 0;
|
|
2148
2193
|
while (vwStart < wordGroups.length) {
|
|
2149
2194
|
let vwEnd = vwStart;
|
|
@@ -2165,9 +2210,11 @@ class AmLyrics extends i {
|
|
|
2165
2210
|
const combinedDuration = combinedEnd - combinedStart;
|
|
2166
2211
|
const isCJK = /[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(combinedText);
|
|
2167
2212
|
const isRTL = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\u0590-\u05FF]/.test(combinedText);
|
|
2213
|
+
if (isRTL)
|
|
2214
|
+
lineIsRTL = true;
|
|
2168
2215
|
const hasHyphen = combinedText.includes('-');
|
|
2169
2216
|
const wordLen = combinedText.length;
|
|
2170
|
-
let isGrowableVW = !isCJK && !isRTL && !hasHyphen && wordLen > 0 && wordLen <=
|
|
2217
|
+
let isGrowableVW = !isCJK && !isRTL && !hasHyphen && wordLen > 0 && wordLen <= 7;
|
|
2171
2218
|
if (isGrowableVW) {
|
|
2172
2219
|
if (wordLen < 3) {
|
|
2173
2220
|
isGrowableVW =
|
|
@@ -2178,7 +2225,8 @@ class AmLyrics extends i {
|
|
|
2178
2225
|
combinedDuration >= 850 && combinedDuration >= wordLen * 190;
|
|
2179
2226
|
}
|
|
2180
2227
|
}
|
|
2181
|
-
const
|
|
2228
|
+
const isLineSynced = line.isWordSynced === false || line.text.some(s => s.lineSynced);
|
|
2229
|
+
const isGlowingVW = isGrowableVW && !isLineSynced;
|
|
2182
2230
|
let charOff = 0;
|
|
2183
2231
|
for (let gi = vwStart; gi <= vwEnd; gi += 1) {
|
|
2184
2232
|
groupGrowable[gi] = isGrowableVW;
|
|
@@ -2202,6 +2250,7 @@ class AmLyrics extends i {
|
|
|
2202
2250
|
vwCharOffset,
|
|
2203
2251
|
vwStartMs,
|
|
2204
2252
|
vwEndMs,
|
|
2253
|
+
lineIsRTL,
|
|
2205
2254
|
};
|
|
2206
2255
|
});
|
|
2207
2256
|
}
|
|
@@ -2282,15 +2331,17 @@ class AmLyrics extends i {
|
|
|
2282
2331
|
clearPreActiveClasses(exceptLineIndex = null) {
|
|
2283
2332
|
if (!this.lyricsContainer)
|
|
2284
2333
|
return;
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
.forEach(element => {
|
|
2288
|
-
const lineElement = element;
|
|
2334
|
+
const keptLines = [];
|
|
2335
|
+
for (const lineElement of this.preActiveLineElements) {
|
|
2289
2336
|
const lineIndex = AmLyrics.getLineIndexFromElement(lineElement);
|
|
2290
|
-
if (lineIndex
|
|
2337
|
+
if (lineIndex === exceptLineIndex) {
|
|
2338
|
+
keptLines.push(lineElement);
|
|
2339
|
+
}
|
|
2340
|
+
else {
|
|
2291
2341
|
lineElement.classList.remove('pre-active');
|
|
2292
2342
|
}
|
|
2293
|
-
}
|
|
2343
|
+
}
|
|
2344
|
+
this.preActiveLineElements = keptLines;
|
|
2294
2345
|
}
|
|
2295
2346
|
getPrimaryActiveLineIndex(activeIndices) {
|
|
2296
2347
|
if (activeIndices.length === 0)
|
|
@@ -2740,6 +2791,7 @@ class AmLyrics extends i {
|
|
|
2740
2791
|
// Clean up any lingering scroll animations before smooth scroll
|
|
2741
2792
|
for (const line of animatingLines) {
|
|
2742
2793
|
line.classList.remove('scroll-animate');
|
|
2794
|
+
line.style.removeProperty('will-change');
|
|
2743
2795
|
line.style.removeProperty('--scroll-delta');
|
|
2744
2796
|
line.style.removeProperty('--lyrics-line-delay');
|
|
2745
2797
|
line.style.removeProperty('--scroll-duration');
|
|
@@ -2798,6 +2850,7 @@ class AmLyrics extends i {
|
|
|
2798
2850
|
// --- Step 4: Re-add scroll-animate class to start fresh animations ---
|
|
2799
2851
|
for (const line of newAnimatingLines) {
|
|
2800
2852
|
line.classList.add('scroll-animate');
|
|
2853
|
+
line.style.willChange = 'transform';
|
|
2801
2854
|
animatingLines.push(line);
|
|
2802
2855
|
}
|
|
2803
2856
|
animState.isAnimating = true;
|
|
@@ -2814,6 +2867,7 @@ class AmLyrics extends i {
|
|
|
2814
2867
|
for (let i = 0; i < animatingLines.length; i += 1) {
|
|
2815
2868
|
const line = animatingLines[i];
|
|
2816
2869
|
line.classList.remove('scroll-animate');
|
|
2870
|
+
line.style.removeProperty('will-change');
|
|
2817
2871
|
line.style.removeProperty('--scroll-delta');
|
|
2818
2872
|
line.style.removeProperty('--lyrics-line-delay');
|
|
2819
2873
|
line.style.removeProperty('--scroll-duration');
|
|
@@ -2842,12 +2896,14 @@ class AmLyrics extends i {
|
|
|
2842
2896
|
'next-3',
|
|
2843
2897
|
'next-4',
|
|
2844
2898
|
];
|
|
2845
|
-
// Remove old position classes
|
|
2846
|
-
this.
|
|
2847
|
-
.
|
|
2848
|
-
|
|
2899
|
+
// Remove old position classes from tracked elements
|
|
2900
|
+
for (const el of this.positionedLineElements) {
|
|
2901
|
+
el.classList.remove(...positionClasses);
|
|
2902
|
+
}
|
|
2903
|
+
this.positionedLineElements = [];
|
|
2849
2904
|
// Add new position classes
|
|
2850
2905
|
lineToScroll.classList.add('lyrics-activest');
|
|
2906
|
+
this.positionedLineElements.push(lineToScroll);
|
|
2851
2907
|
const lineElements = Array.from(this.lyricsContainer.querySelectorAll('.lyrics-line'));
|
|
2852
2908
|
const scrollLineIndex = lineElements.indexOf(lineToScroll);
|
|
2853
2909
|
for (let i = Math.max(0, scrollLineIndex - 4); i <= Math.min(lineElements.length - 1, scrollLineIndex + 4); i += 1) {
|
|
@@ -2862,6 +2918,7 @@ class AmLyrics extends i {
|
|
|
2862
2918
|
element.classList.add(`prev-${Math.abs(position)}`);
|
|
2863
2919
|
else
|
|
2864
2920
|
element.classList.add(`next-${position}`);
|
|
2921
|
+
this.positionedLineElements.push(element);
|
|
2865
2922
|
}
|
|
2866
2923
|
}
|
|
2867
2924
|
}
|
|
@@ -2881,11 +2938,12 @@ class AmLyrics extends i {
|
|
|
2881
2938
|
paddingTop) < 1) {
|
|
2882
2939
|
return;
|
|
2883
2940
|
}
|
|
2884
|
-
// Skip scroll if near the bottom of content
|
|
2885
|
-
if (!forceScroll) {
|
|
2941
|
+
// Skip scroll if near the bottom of content and we aren't trying to scroll back up
|
|
2942
|
+
if (!forceScroll && !activeLine.classList.contains('lyrics-footer')) {
|
|
2886
2943
|
const parent = this.lyricsContainer;
|
|
2887
2944
|
const atBottom = parent.scrollTop + parent.clientHeight >= parent.scrollHeight - 50;
|
|
2888
|
-
|
|
2945
|
+
const targetTop = Math.max(0, -(paddingTop - activeLine.offsetTop));
|
|
2946
|
+
if (atBottom && targetTop > parent.scrollTop - 50) {
|
|
2889
2947
|
return;
|
|
2890
2948
|
}
|
|
2891
2949
|
}
|
|
@@ -2906,7 +2964,7 @@ class AmLyrics extends i {
|
|
|
2906
2964
|
* Update syllable highlight animation - apply CSS wipe animation
|
|
2907
2965
|
* (Exact copy from YouLyPlus _updateSyllableAnimation)
|
|
2908
2966
|
*/
|
|
2909
|
-
static updateSyllableAnimation(syllable) {
|
|
2967
|
+
static updateSyllableAnimation(syllable, elapsedTimeMs = 0) {
|
|
2910
2968
|
if (syllable.classList.contains('highlight'))
|
|
2911
2969
|
return;
|
|
2912
2970
|
const { classList } = syllable;
|
|
@@ -2934,8 +2992,8 @@ class AmLyrics extends i {
|
|
|
2934
2992
|
const baseDelayPerChar = finalDuration * 0.09;
|
|
2935
2993
|
const growDurationMs = finalDuration * 1.5;
|
|
2936
2994
|
allWordCharSpans.forEach(span => {
|
|
2937
|
-
const
|
|
2938
|
-
const
|
|
2995
|
+
const matrixScale = span.dataset.matrixScale || '1.1';
|
|
2996
|
+
const charOffsetX = span.dataset.charOffsetX || '0';
|
|
2939
2997
|
const shadowIntensity = span.dataset.shadowIntensity || '0.6';
|
|
2940
2998
|
const translateYPeak = span.dataset.translateYPeak || '-2';
|
|
2941
2999
|
const syllableCharIndex = parseFloat(span.dataset.syllableCharIndex || '0');
|
|
@@ -2943,13 +3001,13 @@ class AmLyrics extends i {
|
|
|
2943
3001
|
charAnimationsMap.set(span, `grow-dynamic ${growDurationMs}ms ease-in-out ${growDelay}ms forwards`);
|
|
2944
3002
|
styleUpdates.push({
|
|
2945
3003
|
element: span,
|
|
2946
|
-
property: '--
|
|
2947
|
-
value:
|
|
3004
|
+
property: '--matrix-scale',
|
|
3005
|
+
value: matrixScale,
|
|
2948
3006
|
});
|
|
2949
3007
|
styleUpdates.push({
|
|
2950
3008
|
element: span,
|
|
2951
|
-
property: '--
|
|
2952
|
-
value:
|
|
3009
|
+
property: '--char-offset-x',
|
|
3010
|
+
value: `${charOffsetX}px`,
|
|
2953
3011
|
});
|
|
2954
3012
|
styleUpdates.push({
|
|
2955
3013
|
element: span,
|
|
@@ -2959,7 +3017,7 @@ class AmLyrics extends i {
|
|
|
2959
3017
|
styleUpdates.push({
|
|
2960
3018
|
element: span,
|
|
2961
3019
|
property: '--translate-y-peak',
|
|
2962
|
-
value: `${translateYPeak}`,
|
|
3020
|
+
value: `${translateYPeak}px`,
|
|
2963
3021
|
});
|
|
2964
3022
|
});
|
|
2965
3023
|
}
|
|
@@ -2968,7 +3026,7 @@ class AmLyrics extends i {
|
|
|
2968
3026
|
charSpans.forEach((span, charIndex) => {
|
|
2969
3027
|
const startPct = parseFloat(span.dataset.wipeStart || '0');
|
|
2970
3028
|
const durationPct = parseFloat(span.dataset.wipeDuration || '0');
|
|
2971
|
-
const wipeDelay = syllableDurationMs * startPct;
|
|
3029
|
+
const wipeDelay = syllableDurationMs * startPct - elapsedTimeMs;
|
|
2972
3030
|
const wipeDuration = syllableDurationMs * durationPct;
|
|
2973
3031
|
const useStartAnimation = isFirstInContainer && charIndex === 0;
|
|
2974
3032
|
let charWipeAnimation = 'wipe';
|
|
@@ -2984,9 +3042,9 @@ class AmLyrics extends i {
|
|
|
2984
3042
|
animationParts.push(existingAnimation.split(',')[0].trim());
|
|
2985
3043
|
}
|
|
2986
3044
|
if (charIndex > 0) {
|
|
2987
|
-
const arrivalTime = span.dataset.preWipeArrival
|
|
3045
|
+
const arrivalTime = (span.dataset.preWipeArrival
|
|
2988
3046
|
? parseFloat(span.dataset.preWipeArrival)
|
|
2989
|
-
:
|
|
3047
|
+
: syllableDurationMs * startPct) - elapsedTimeMs;
|
|
2990
3048
|
const constantDuration = parseFloat(span.dataset.preWipeDuration || '100');
|
|
2991
3049
|
const animDelay = arrivalTime - constantDuration;
|
|
2992
3050
|
if (constantDuration > 0) {
|
|
@@ -3016,12 +3074,13 @@ class AmLyrics extends i {
|
|
|
3016
3074
|
return;
|
|
3017
3075
|
const currentWipeAnimation = isGap ? 'fade-gap' : wipeAnimation;
|
|
3018
3076
|
// eslint-disable-next-line no-param-reassign
|
|
3019
|
-
syllable.style.animation = `${currentWipeAnimation} ${visualDuration}ms ${isGap ? 'ease-out' : 'linear'} forwards`;
|
|
3077
|
+
syllable.style.animation = `${currentWipeAnimation} ${visualDuration}ms ${isGap ? 'ease-out' : 'linear'} ${-elapsedTimeMs}ms forwards`;
|
|
3020
3078
|
}
|
|
3021
3079
|
// --- WRITE PHASE ---
|
|
3022
3080
|
classList.remove('pre-highlight');
|
|
3023
3081
|
classList.add('highlight');
|
|
3024
3082
|
for (const [span, animationString] of charAnimationsMap.entries()) {
|
|
3083
|
+
span.style.willChange = 'transform';
|
|
3025
3084
|
span.style.animation = animationString;
|
|
3026
3085
|
}
|
|
3027
3086
|
// Apply style updates
|
|
@@ -3048,6 +3107,7 @@ class AmLyrics extends i {
|
|
|
3048
3107
|
syllable.querySelectorAll('span.char').forEach(span => {
|
|
3049
3108
|
const el = span;
|
|
3050
3109
|
el.style.animation = '';
|
|
3110
|
+
el.style.willChange = '';
|
|
3051
3111
|
el.style.transition = 'none';
|
|
3052
3112
|
el.style.backgroundColor = 'var(--lyplus-text-secondary)';
|
|
3053
3113
|
});
|
|
@@ -3061,6 +3121,7 @@ class AmLyrics extends i {
|
|
|
3061
3121
|
const el = span;
|
|
3062
3122
|
el.style.removeProperty('background-color');
|
|
3063
3123
|
el.style.removeProperty('transition');
|
|
3124
|
+
el.style.removeProperty('will-change');
|
|
3064
3125
|
});
|
|
3065
3126
|
});
|
|
3066
3127
|
}
|
|
@@ -3090,7 +3151,7 @@ class AmLyrics extends i {
|
|
|
3090
3151
|
const syllable = syllables[i];
|
|
3091
3152
|
const startTime = parseFloat(syllable.getAttribute('data-start-time') || '0');
|
|
3092
3153
|
const endTime = parseFloat(syllable.getAttribute('data-end-time') || '0');
|
|
3093
|
-
if (startTime) {
|
|
3154
|
+
if (Number.isFinite(startTime) && Number.isFinite(endTime)) {
|
|
3094
3155
|
const { classList } = syllable;
|
|
3095
3156
|
const hasHighlight = classList.contains('highlight');
|
|
3096
3157
|
const hasFinished = classList.contains('finished');
|
|
@@ -3114,7 +3175,7 @@ class AmLyrics extends i {
|
|
|
3114
3175
|
if (currentTimeMs >= startTime && currentTimeMs <= endTime) {
|
|
3115
3176
|
// Currently active
|
|
3116
3177
|
if (!hasHighlight) {
|
|
3117
|
-
AmLyrics.updateSyllableAnimation(syllable);
|
|
3178
|
+
AmLyrics.updateSyllableAnimation(syllable, currentTimeMs - startTime);
|
|
3118
3179
|
}
|
|
3119
3180
|
if (hasFinished) {
|
|
3120
3181
|
classList.remove('finished');
|
|
@@ -3124,7 +3185,7 @@ class AmLyrics extends i {
|
|
|
3124
3185
|
// Finished
|
|
3125
3186
|
if (!hasFinished) {
|
|
3126
3187
|
if (!hasHighlight) {
|
|
3127
|
-
AmLyrics.updateSyllableAnimation(syllable);
|
|
3188
|
+
AmLyrics.updateSyllableAnimation(syllable, currentTimeMs - startTime);
|
|
3128
3189
|
}
|
|
3129
3190
|
classList.add('finished');
|
|
3130
3191
|
}
|
|
@@ -3376,7 +3437,6 @@ class AmLyrics extends i {
|
|
|
3376
3437
|
}
|
|
3377
3438
|
// Set both old internal CSS variables (for backward compatibility)
|
|
3378
3439
|
// and new public CSS variables (which take precedence)
|
|
3379
|
-
this.style.setProperty('--hover-background-color', this.hoverBackgroundColor);
|
|
3380
3440
|
this.style.setProperty('--highlight-color', this.highlightColor);
|
|
3381
3441
|
const sourceLabel = this.lyricsSource ?? 'Unavailable';
|
|
3382
3442
|
const isUnsynced = this.cachedIsUnsynced;
|
|
@@ -3418,7 +3478,7 @@ class AmLyrics extends i {
|
|
|
3418
3478
|
syllable.romanizedText &&
|
|
3419
3479
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
3420
3480
|
? b `<span
|
|
3421
|
-
class="lyrics-syllable transliteration ${syllable.lineSynced
|
|
3481
|
+
class="lyrics-syllable transliteration no-chars ${syllable.lineSynced
|
|
3422
3482
|
? 'line-synced'
|
|
3423
3483
|
: ''}"
|
|
3424
3484
|
data-start-time="${startTimeMs}"
|
|
@@ -3429,21 +3489,24 @@ class AmLyrics extends i {
|
|
|
3429
3489
|
>${syllable.romanizedText}</span
|
|
3430
3490
|
>`
|
|
3431
3491
|
: '';
|
|
3432
|
-
return b `<span class="lyrics-word"
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3492
|
+
return b `<span class="lyrics-word"
|
|
3493
|
+
><span
|
|
3494
|
+
class="lyrics-syllable-wrap${bgRomanizedText
|
|
3495
|
+
? ' has-transliteration'
|
|
3496
|
+
: ''}"
|
|
3497
|
+
><span
|
|
3498
|
+
class="lyrics-syllable no-chars${syllable.lineSynced
|
|
3499
|
+
? ' line-synced'
|
|
3437
3500
|
: ''}"
|
|
3438
3501
|
data-start-time="${startTimeMs}"
|
|
3439
3502
|
data-end-time="${endTimeMs}"
|
|
3440
3503
|
data-duration="${durationMs}"
|
|
3441
3504
|
data-syllable-index="${syllableIndex}"
|
|
3505
|
+
data-wipe-ratio="1"
|
|
3442
3506
|
>${syllable.text}</span
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
</span>`;
|
|
3507
|
+
>${bgRomanizedText}</span
|
|
3508
|
+
></span
|
|
3509
|
+
>`;
|
|
3447
3510
|
})}
|
|
3448
3511
|
</p>`
|
|
3449
3512
|
: '';
|
|
@@ -3461,8 +3524,11 @@ class AmLyrics extends i {
|
|
|
3461
3524
|
const vwFullText = lineData?.vwFullText ?? [];
|
|
3462
3525
|
const vwFullDuration = lineData?.vwFullDuration ?? [];
|
|
3463
3526
|
const vwCharOffset = lineData?.vwCharOffset ?? [];
|
|
3527
|
+
const lineIsRTL = lineData?.lineIsRTL ?? false;
|
|
3464
3528
|
// Create main vocals using YouLyPlus syllable structure
|
|
3465
|
-
const mainVocalElement = b `<p
|
|
3529
|
+
const mainVocalElement = b `<p
|
|
3530
|
+
class="main-vocal-container ${lineIsRTL ? 'rtl-text' : ''}"
|
|
3531
|
+
>
|
|
3466
3532
|
${wordGroups.map((group, groupIdx) => {
|
|
3467
3533
|
const isGrowable = groupGrowable[groupIdx];
|
|
3468
3534
|
const isGlowing = groupGlowing[groupIdx];
|
|
@@ -3472,12 +3538,21 @@ class AmLyrics extends i {
|
|
|
3472
3538
|
const wordNumChars = wordText.length;
|
|
3473
3539
|
const groupCharOffset = isGrowable ? vwCharOffset[groupIdx] : 0;
|
|
3474
3540
|
let sylCharAccumulator = 0;
|
|
3541
|
+
const groupText = group.map(s => s.text).join('');
|
|
3542
|
+
const shouldAllowBreak = groupText.trim().length >= 16 ||
|
|
3543
|
+
/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(groupText);
|
|
3544
|
+
// Calculate dynamic rise duration based on the audio duration of the word
|
|
3545
|
+
const wordStartTimeMs = group[0].timestamp;
|
|
3546
|
+
const wordEndTimeMs = group[group.length - 1].endtime;
|
|
3547
|
+
const actualDurationMs = wordEndTimeMs - wordStartTimeMs;
|
|
3548
|
+
// Base float is 0.8s, plus a portion of the audio duration, capped between 1.0s and 2.5s
|
|
3549
|
+
const riseDuration = Math.max(1.2, Math.min(2.5, 1.2 + (actualDurationMs / 1000) * 0.6));
|
|
3475
3550
|
return b `<span
|
|
3476
|
-
class="lyrics-word
|
|
3477
|
-
? 'glowing'
|
|
3478
|
-
: ''}
|
|
3479
|
-
|
|
3480
|
-
|
|
3551
|
+
class="lyrics-word${isGrowable ? ' growable' : ''}${isGlowing
|
|
3552
|
+
? ' glowing'
|
|
3553
|
+
: ''}${shouldAllowBreak ? ' allow-break' : ''}"
|
|
3554
|
+
style="--rise-duration: ${riseDuration}s"
|
|
3555
|
+
>${group.map((syllable, sylIdx) => {
|
|
3481
3556
|
const startTimeMs = syllable.timestamp;
|
|
3482
3557
|
const endTimeMs = syllable.endtime;
|
|
3483
3558
|
const durationMs = endTimeMs - startTimeMs;
|
|
@@ -3486,7 +3561,7 @@ class AmLyrics extends i {
|
|
|
3486
3561
|
syllable.romanizedText &&
|
|
3487
3562
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
3488
3563
|
? b `<span
|
|
3489
|
-
class="lyrics-syllable transliteration ${groupLineSynced
|
|
3564
|
+
class="lyrics-syllable transliteration no-chars ${groupLineSynced
|
|
3490
3565
|
? 'line-synced'
|
|
3491
3566
|
: ''}"
|
|
3492
3567
|
data-start-time="${startTimeMs}"
|
|
@@ -3563,17 +3638,22 @@ class AmLyrics extends i {
|
|
|
3563
3638
|
data-wipe-duration="${(1 / numCharsInSyllable).toFixed(4)}"
|
|
3564
3639
|
data-horizontal-offset="${horizontalOffset.toFixed(2)}"
|
|
3565
3640
|
data-max-scale="${charMaxScale.toFixed(3)}"
|
|
3641
|
+
data-matrix-scale="${(charMaxScale * 0.98).toFixed(3)}"
|
|
3642
|
+
data-char-offset-x="${(horizontalOffset * 0.98).toFixed(2)}"
|
|
3566
3643
|
data-shadow-intensity="${charShadowIntensity.toFixed(3)}"
|
|
3567
3644
|
data-translate-y-peak="${charTranslateYPeak.toFixed(3)}"
|
|
3568
3645
|
>${char}</span
|
|
3569
3646
|
>`;
|
|
3570
3647
|
})}`;
|
|
3571
3648
|
}
|
|
3572
|
-
return b `<span
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
? 'line-synced'
|
|
3649
|
+
return b `<span
|
|
3650
|
+
class="lyrics-syllable-wrap${romanizedText
|
|
3651
|
+
? ' has-transliteration'
|
|
3576
3652
|
: ''}"
|
|
3653
|
+
><span
|
|
3654
|
+
class="lyrics-syllable${groupLineSynced
|
|
3655
|
+
? ' line-synced'
|
|
3656
|
+
: ''}${isGrowable ? ' has-chars' : ' no-chars'}"
|
|
3577
3657
|
data-start-time="${startTimeMs}"
|
|
3578
3658
|
data-end-time="${endTimeMs}"
|
|
3579
3659
|
data-duration="${durationMs}"
|
|
@@ -3581,11 +3661,10 @@ class AmLyrics extends i {
|
|
|
3581
3661
|
data-syllable-index="${sylIdx}"
|
|
3582
3662
|
data-wipe-ratio="1"
|
|
3583
3663
|
>${syllableContent}</span
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
</span>`;
|
|
3664
|
+
>${romanizedText}</span
|
|
3665
|
+
>`;
|
|
3666
|
+
})}</span
|
|
3667
|
+
>`;
|
|
3589
3668
|
})}
|
|
3590
3669
|
</p>`;
|
|
3591
3670
|
// Translation container (if enabled)
|
|
@@ -3607,7 +3686,11 @@ class AmLyrics extends i {
|
|
|
3607
3686
|
line.romanizedText &&
|
|
3608
3687
|
!line.text.some(s => s.romanizedText) &&
|
|
3609
3688
|
line.romanizedText.trim() !== fullLineText
|
|
3610
|
-
? b `<div
|
|
3689
|
+
? b `<div
|
|
3690
|
+
class="lyrics-romanization-container ${lineIsRTL
|
|
3691
|
+
? 'rtl-text'
|
|
3692
|
+
: ''}"
|
|
3693
|
+
>
|
|
3611
3694
|
${line.romanizedText}
|
|
3612
3695
|
</div>`
|
|
3613
3696
|
: '';
|
|
@@ -3627,42 +3710,37 @@ class AmLyrics extends i {
|
|
|
3627
3710
|
data-end-time="${gapForLine.gapEnd}"
|
|
3628
3711
|
style="--gap-pulse-duration: ${GAP_PULSE_DURATION_MS}ms; --gap-loop-delay: -${gapLoopDelay}ms; --gap-exit-duration: ${GAP_EXIT_LEAD_MS}ms; --gap-exit-scale: ${GAP_MIN_SCALE};"
|
|
3629
3712
|
>
|
|
3630
|
-
<
|
|
3631
|
-
<
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
></span>
|
|
3662
|
-
</span>
|
|
3663
|
-
</span>
|
|
3664
|
-
</p>
|
|
3665
|
-
</div>
|
|
3713
|
+
<p class="main-vocal-container">
|
|
3714
|
+
<span class="lyrics-word"
|
|
3715
|
+
><span class="lyrics-syllable-wrap"
|
|
3716
|
+
><span
|
|
3717
|
+
class="lyrics-syllable"
|
|
3718
|
+
data-start-time="${gapForLine.gapStart}"
|
|
3719
|
+
data-end-time="${gapForLine.gapStart + dotDuration}"
|
|
3720
|
+
data-duration="${dotDuration}"
|
|
3721
|
+
data-wipe-ratio="1"
|
|
3722
|
+
data-syllable-index="0"
|
|
3723
|
+
></span></span
|
|
3724
|
+
><span class="lyrics-syllable-wrap"
|
|
3725
|
+
><span
|
|
3726
|
+
class="lyrics-syllable"
|
|
3727
|
+
data-start-time="${gapForLine.gapStart + dotDuration}"
|
|
3728
|
+
data-end-time="${gapForLine.gapStart + dotDuration * 2}"
|
|
3729
|
+
data-duration="${dotDuration}"
|
|
3730
|
+
data-wipe-ratio="1"
|
|
3731
|
+
data-syllable-index="1"
|
|
3732
|
+
></span></span
|
|
3733
|
+
><span class="lyrics-syllable-wrap"
|
|
3734
|
+
><span
|
|
3735
|
+
class="lyrics-syllable"
|
|
3736
|
+
data-start-time="${gapForLine.gapStart + dotDuration * 2}"
|
|
3737
|
+
data-end-time="${gapForLine.gapEnd}"
|
|
3738
|
+
data-duration="${dotDuration}"
|
|
3739
|
+
data-wipe-ratio="1"
|
|
3740
|
+
data-syllable-index="2"
|
|
3741
|
+
></span></span
|
|
3742
|
+
></span>
|
|
3743
|
+
</p>
|
|
3666
3744
|
</div>`;
|
|
3667
3745
|
}
|
|
3668
3746
|
return b `
|
|
@@ -3671,7 +3749,7 @@ class AmLyrics extends i {
|
|
|
3671
3749
|
id="${lineId}"
|
|
3672
3750
|
class="lyrics-line ${line.alignment === 'end'
|
|
3673
3751
|
? 'singer-right'
|
|
3674
|
-
: 'singer-left'}"
|
|
3752
|
+
: 'singer-left'} ${lineIsRTL ? 'rtl-text' : ''}"
|
|
3675
3753
|
data-start-time="${lineStartTime}"
|
|
3676
3754
|
data-end-time="${lineEndTime}"
|
|
3677
3755
|
@click=${() => this.handleLineClick(line)}
|
|
@@ -3682,11 +3760,11 @@ class AmLyrics extends i {
|
|
|
3682
3760
|
}
|
|
3683
3761
|
}}
|
|
3684
3762
|
>
|
|
3685
|
-
<div class="lyrics-line-container">
|
|
3763
|
+
<div class="lyrics-line-container ${lineIsRTL ? 'rtl-text' : ''}">
|
|
3686
3764
|
${bgPlacement === 'before' ? backgroundVocalElement : ''}
|
|
3687
3765
|
${mainVocalElement}
|
|
3688
3766
|
${bgPlacement === 'after' ? backgroundVocalElement : ''}
|
|
3689
|
-
${
|
|
3767
|
+
${lineRomanizationElement} ${translationElement}
|
|
3690
3768
|
</div>
|
|
3691
3769
|
</div>
|
|
3692
3770
|
`;
|
|
@@ -3799,13 +3877,13 @@ class AmLyrics extends i {
|
|
|
3799
3877
|
${renderContent()}
|
|
3800
3878
|
${!this.isLoading
|
|
3801
3879
|
? b `
|
|
3802
|
-
<footer class="lyrics-footer">
|
|
3880
|
+
<footer class="lyrics-footer lyrics-line">
|
|
3803
3881
|
<div class="footer-content">
|
|
3804
3882
|
<span
|
|
3805
3883
|
class="source-info"
|
|
3806
3884
|
style="display: flex; align-items: center; gap: 8px;"
|
|
3807
3885
|
>
|
|
3808
|
-
|
|
3886
|
+
<b style="font-weight: 750;">Source</b> ${sourceLabel}
|
|
3809
3887
|
${(this.availableSources &&
|
|
3810
3888
|
this.availableSources.length > 1) ||
|
|
3811
3889
|
!this.hasFetchedAllProviders
|
|
@@ -3848,15 +3926,25 @@ class AmLyrics extends i {
|
|
|
3848
3926
|
`
|
|
3849
3927
|
: ''}
|
|
3850
3928
|
</span>
|
|
3851
|
-
|
|
3852
|
-
|
|
3929
|
+
${this.songwriters
|
|
3930
|
+
? b `<span
|
|
3931
|
+
class="songwriters-info"
|
|
3932
|
+
style="margin-top: 4px; font-weight: normal; font-size: 0.9em;"
|
|
3933
|
+
>
|
|
3934
|
+
<b style="font-weight: 750;">Songwriters</b> ${this
|
|
3935
|
+
.songwriters}
|
|
3936
|
+
</span>`
|
|
3937
|
+
: ''}
|
|
3938
|
+
<span class="version-info" style="margin-top: 8px;">
|
|
3939
|
+
<b style="font-weight: 750;">am-lyrics</b> v${VERSION} •
|
|
3853
3940
|
|
|
3854
3941
|
<a
|
|
3855
3942
|
href="https://github.com/uimaxbai/apple-music-web-components"
|
|
3856
3943
|
target="_blank"
|
|
3857
3944
|
rel="noopener noreferrer"
|
|
3858
|
-
|
|
3859
|
-
|
|
3945
|
+
style="display: inline-flex; align-items: center; gap: 4px;"
|
|
3946
|
+
>Star me on GitHub
|
|
3947
|
+
</a>
|
|
3860
3948
|
</span>
|
|
3861
3949
|
</div>
|
|
3862
3950
|
</footer>
|
|
@@ -3893,6 +3981,7 @@ AmLyrics.styles = i$3 `
|
|
|
3893
3981
|
--lyplus-font-size-base: 32px;
|
|
3894
3982
|
--lyplus-font-size-base-grow: 24.5;
|
|
3895
3983
|
--lyplus-font-size-subtext: 0.6em;
|
|
3984
|
+
--char-rise-y: calc(-0.035 * var(--lyplus-font-size-base));
|
|
3896
3985
|
|
|
3897
3986
|
--lyplus-blur-amount: 0.07em;
|
|
3898
3987
|
--lyplus-blur-amount-near: 0.035em;
|
|
@@ -3926,7 +4015,6 @@ AmLyrics.styles = i$3 `
|
|
|
3926
4015
|
-webkit-overflow-scrolling: touch;
|
|
3927
4016
|
box-sizing: border-box;
|
|
3928
4017
|
scrollbar-width: none;
|
|
3929
|
-
transform: translateZ(0);
|
|
3930
4018
|
}
|
|
3931
4019
|
|
|
3932
4020
|
.lyrics-container::-webkit-scrollbar {
|
|
@@ -3937,11 +4025,13 @@ AmLyrics.styles = i$3 `
|
|
|
3937
4025
|
.lyrics-container.touch-scrolling .lyrics-line,
|
|
3938
4026
|
.lyrics-container.touch-scrolling .lyrics-plus-metadata {
|
|
3939
4027
|
transition: none !important;
|
|
4028
|
+
filter: none !important;
|
|
3940
4029
|
}
|
|
3941
4030
|
|
|
3942
4031
|
/* Apply smooth gliding transition for mouse-wheel scrolling */
|
|
3943
4032
|
.lyrics-container.wheel-scrolling .lyrics-line {
|
|
3944
4033
|
transition: transform 0.3s ease-out !important;
|
|
4034
|
+
filter: none !important;
|
|
3945
4035
|
}
|
|
3946
4036
|
|
|
3947
4037
|
.lyrics-line.scroll-animate {
|
|
@@ -3968,18 +4058,13 @@ AmLyrics.styles = i$3 `
|
|
|
3968
4058
|
font-size: var(--lyplus-font-size-base);
|
|
3969
4059
|
cursor: pointer;
|
|
3970
4060
|
transform-origin: left;
|
|
3971
|
-
transform: translateZ(1px);
|
|
3972
4061
|
transition:
|
|
3973
4062
|
opacity 0.3s ease,
|
|
3974
4063
|
transform 0.4s cubic-bezier(0.41, 0, 0.12, 0.99)
|
|
3975
4064
|
var(--lyrics-line-delay, 0ms),
|
|
3976
4065
|
filter 0.3s ease;
|
|
3977
|
-
will-change: transform, filter, opacity;
|
|
3978
4066
|
content-visibility: auto;
|
|
3979
4067
|
text-rendering: optimizeLegibility;
|
|
3980
|
-
overflow-wrap: break-word;
|
|
3981
|
-
mix-blend-mode: lighten;
|
|
3982
|
-
border-radius: var(--lyplus-border-radius-base);
|
|
3983
4068
|
}
|
|
3984
4069
|
|
|
3985
4070
|
.lyrics-line:not(.scroll-animate) {
|
|
@@ -3999,8 +4084,7 @@ AmLyrics.styles = i$3 `
|
|
|
3999
4084
|
|
|
4000
4085
|
.lyrics-line.active .lyrics-line-container,
|
|
4001
4086
|
.lyrics-line.pre-active .lyrics-line-container {
|
|
4002
|
-
transform: scale3d(1.001, 1.001, 1);
|
|
4003
|
-
will-change: transform;
|
|
4087
|
+
transform: scale3d(1.001, 1.001, 1) translateZ(0);
|
|
4004
4088
|
transition:
|
|
4005
4089
|
transform 0.5s ease,
|
|
4006
4090
|
background-color 0.18s,
|
|
@@ -4045,12 +4129,10 @@ AmLyrics.styles = i$3 `
|
|
|
4045
4129
|
.lyrics-line.active {
|
|
4046
4130
|
opacity: 1;
|
|
4047
4131
|
color: var(--lyplus-text-primary);
|
|
4048
|
-
will-change: transform, opacity;
|
|
4049
4132
|
}
|
|
4050
4133
|
|
|
4051
4134
|
.lyrics-line.pre-active {
|
|
4052
4135
|
opacity: 1;
|
|
4053
|
-
will-change: transform, opacity;
|
|
4054
4136
|
}
|
|
4055
4137
|
|
|
4056
4138
|
.lyrics-line.singer-right {
|
|
@@ -4064,6 +4146,18 @@ AmLyrics.styles = i$3 `
|
|
|
4064
4146
|
|
|
4065
4147
|
.lyrics-line.rtl-text {
|
|
4066
4148
|
direction: rtl;
|
|
4149
|
+
text-align: right !important;
|
|
4150
|
+
transform-origin: right;
|
|
4151
|
+
}
|
|
4152
|
+
|
|
4153
|
+
.lyrics-line.rtl-text .lyrics-line-container,
|
|
4154
|
+
.lyrics-line.rtl-text .main-vocal-container {
|
|
4155
|
+
transform-origin: right;
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
.lyrics-line.rtl-text .lyrics-romanization-container,
|
|
4159
|
+
.lyrics-line.rtl-text .lyrics-translation-container {
|
|
4160
|
+
text-align: right;
|
|
4067
4161
|
}
|
|
4068
4162
|
|
|
4069
4163
|
/* --- Unsynced (Plain Text) Lyrics Overrides --- */
|
|
@@ -4095,7 +4189,8 @@ AmLyrics.styles = i$3 `
|
|
|
4095
4189
|
|
|
4096
4190
|
@media (hover: hover) and (pointer: fine) {
|
|
4097
4191
|
.lyrics-line:hover {
|
|
4098
|
-
|
|
4192
|
+
filter: none !important;
|
|
4193
|
+
opacity: 1 !important;
|
|
4099
4194
|
}
|
|
4100
4195
|
.lyrics-container.is-unsynced .lyrics-line:hover {
|
|
4101
4196
|
background: transparent !important;
|
|
@@ -4125,6 +4220,7 @@ AmLyrics.styles = i$3 `
|
|
|
4125
4220
|
|
|
4126
4221
|
/* Unblur all lines when user is scrolling */
|
|
4127
4222
|
.lyrics-container.user-scrolling .lyrics-line {
|
|
4223
|
+
transition: none !important;
|
|
4128
4224
|
filter: none !important;
|
|
4129
4225
|
opacity: 0.8 !important;
|
|
4130
4226
|
}
|
|
@@ -4141,6 +4237,7 @@ AmLyrics.styles = i$3 `
|
|
|
4141
4237
|
.lyrics-word:not(.allow-break) {
|
|
4142
4238
|
display: inline-block;
|
|
4143
4239
|
vertical-align: baseline;
|
|
4240
|
+
white-space: nowrap;
|
|
4144
4241
|
}
|
|
4145
4242
|
|
|
4146
4243
|
.lyrics-word.allow-break {
|
|
@@ -4151,7 +4248,7 @@ AmLyrics.styles = i$3 `
|
|
|
4151
4248
|
display: inline;
|
|
4152
4249
|
}
|
|
4153
4250
|
|
|
4154
|
-
.lyrics-syllable-wrap
|
|
4251
|
+
.lyrics-syllable-wrap.has-transliteration {
|
|
4155
4252
|
display: inline-flex;
|
|
4156
4253
|
flex-direction: column;
|
|
4157
4254
|
align-items: start;
|
|
@@ -4179,7 +4276,7 @@ AmLyrics.styles = i$3 `
|
|
|
4179
4276
|
transition: transform 1s ease !important;
|
|
4180
4277
|
}
|
|
4181
4278
|
|
|
4182
|
-
.lyrics-syllable.finished
|
|
4279
|
+
.lyrics-syllable.finished.has-chars {
|
|
4183
4280
|
background-color: transparent;
|
|
4184
4281
|
}
|
|
4185
4282
|
|
|
@@ -4188,19 +4285,16 @@ AmLyrics.styles = i$3 `
|
|
|
4188
4285
|
}
|
|
4189
4286
|
|
|
4190
4287
|
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable {
|
|
4191
|
-
transform: translateY(0.001%) translateZ(1px);
|
|
4192
4288
|
transition:
|
|
4193
4289
|
transform 1s ease,
|
|
4194
4290
|
background-color 0.5s,
|
|
4195
4291
|
color 0.5s;
|
|
4196
|
-
will-change: transform, background;
|
|
4197
4292
|
}
|
|
4198
4293
|
|
|
4199
4294
|
/* --- Wipe Highlight Effect --- */
|
|
4295
|
+
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable.highlight.no-chars,
|
|
4200
4296
|
.lyrics-line.active:not(.lyrics-gap)
|
|
4201
|
-
.lyrics-syllable.highlight
|
|
4202
|
-
.lyrics-line.active:not(.lyrics-gap)
|
|
4203
|
-
.lyrics-syllable.pre-highlight:not(:has(.char)) {
|
|
4297
|
+
.lyrics-syllable.pre-highlight.no-chars {
|
|
4204
4298
|
background-repeat: no-repeat;
|
|
4205
4299
|
background-image:
|
|
4206
4300
|
linear-gradient(
|
|
@@ -4242,11 +4336,19 @@ AmLyrics.styles = i$3 `
|
|
|
4242
4336
|
right;
|
|
4243
4337
|
}
|
|
4244
4338
|
|
|
4339
|
+
/* Non-growable words float up with a gentle curve */
|
|
4245
4340
|
.lyrics-line.active:not(.lyrics-gap)
|
|
4246
4341
|
.lyrics-word:not(.growable)
|
|
4247
|
-
.lyrics-syllable.highlight
|
|
4342
|
+
.lyrics-syllable.highlight {
|
|
4343
|
+
transform: translateY(-3.5%);
|
|
4344
|
+
transition:
|
|
4345
|
+
transform var(--rise-duration, 1.5s) cubic-bezier(0.22, 1, 0.36, 1),
|
|
4346
|
+
background-color 0.5s,
|
|
4347
|
+
color 0.5s;
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4248
4350
|
.lyrics-word.growable .lyrics-syllable.cleanup .char {
|
|
4249
|
-
transform: translateY(-3.5%)
|
|
4351
|
+
transform: translateY(-3.5%);
|
|
4250
4352
|
}
|
|
4251
4353
|
|
|
4252
4354
|
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable.highlight.finished {
|
|
@@ -4273,7 +4375,7 @@ AmLyrics.styles = i$3 `
|
|
|
4273
4375
|
}
|
|
4274
4376
|
|
|
4275
4377
|
/* Syllable with chars: make syllable transparent, chars handle color */
|
|
4276
|
-
.lyrics-line .lyrics-syllable
|
|
4378
|
+
.lyrics-line .lyrics-syllable.has-chars:not(.finished) {
|
|
4277
4379
|
background-color: transparent;
|
|
4278
4380
|
color: transparent;
|
|
4279
4381
|
}
|
|
@@ -4286,6 +4388,7 @@ AmLyrics.styles = i$3 `
|
|
|
4286
4388
|
font-feature-settings: 'liga' 0;
|
|
4287
4389
|
background-clip: text;
|
|
4288
4390
|
-webkit-background-clip: text;
|
|
4391
|
+
backface-visibility: hidden;
|
|
4289
4392
|
transition:
|
|
4290
4393
|
color 0.7s,
|
|
4291
4394
|
background-color 0.7s,
|
|
@@ -4321,11 +4424,9 @@ AmLyrics.styles = i$3 `
|
|
|
4321
4424
|
-0.5em 0%,
|
|
4322
4425
|
-0.25em 0%;
|
|
4323
4426
|
transform-origin: 50% 80%;
|
|
4324
|
-
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
4325
4427
|
transition:
|
|
4326
4428
|
transform 0.7s ease,
|
|
4327
4429
|
color 0.18s;
|
|
4328
|
-
will-change: background, transform;
|
|
4329
4430
|
}
|
|
4330
4431
|
|
|
4331
4432
|
.lyrics-line.active .lyrics-syllable span.char.highlight {
|
|
@@ -4377,6 +4478,8 @@ AmLyrics.styles = i$3 `
|
|
|
4377
4478
|
box-sizing: content-box;
|
|
4378
4479
|
background-clip: unset;
|
|
4379
4480
|
transform-origin: top;
|
|
4481
|
+
content-visibility: visible !important;
|
|
4482
|
+
contain: none !important;
|
|
4380
4483
|
transition:
|
|
4381
4484
|
opacity 160ms ease-out,
|
|
4382
4485
|
transform var(--scroll-duration, 280ms) var(--lyrics-line-delay, 0ms);
|
|
@@ -4387,41 +4490,35 @@ AmLyrics.styles = i$3 `
|
|
|
4387
4490
|
transition:
|
|
4388
4491
|
opacity 160ms ease-out,
|
|
4389
4492
|
transform var(--scroll-duration, 280ms);
|
|
4390
|
-
will-change: opacity;
|
|
4391
4493
|
}
|
|
4392
4494
|
|
|
4393
4495
|
/* Exiting state: quickly collapse width and height so dots don't distort page, or remove max-height transition */
|
|
4394
4496
|
.lyrics-gap.gap-exiting {
|
|
4395
4497
|
opacity: 1;
|
|
4396
|
-
transition: transform var(--scroll-duration, 280ms);
|
|
4397
4498
|
}
|
|
4398
4499
|
|
|
4399
4500
|
.lyrics-gap .main-vocal-container {
|
|
4400
|
-
transform: translateY(-25%) scale(1)
|
|
4501
|
+
transform: translateY(-25%) scale(1);
|
|
4401
4502
|
transition: transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
4402
4503
|
}
|
|
4403
4504
|
|
|
4404
|
-
/* Jump animation plays during exit */
|
|
4405
|
-
.lyrics-gap.gap-exiting .main-vocal-container {
|
|
4406
|
-
animation: gap-ended var(--gap-exit-duration, 360ms)
|
|
4407
|
-
cubic-bezier(0.33, 1, 0.68, 1) forwards;
|
|
4408
|
-
}
|
|
4409
|
-
|
|
4410
4505
|
.lyrics-gap:not(.active):not(.gap-exiting) .main-vocal-container {
|
|
4411
|
-
transform: translateY(-25%) scale(0)
|
|
4412
|
-
}
|
|
4413
|
-
|
|
4414
|
-
.lyrics-gap:not(.active):not(.gap-exiting)
|
|
4415
|
-
.main-vocal-container
|
|
4416
|
-
.lyrics-word {
|
|
4417
|
-
animation-play-state: paused;
|
|
4506
|
+
transform: translateY(-25%) scale(0);
|
|
4418
4507
|
}
|
|
4419
4508
|
|
|
4420
|
-
|
|
4509
|
+
/* Pulse — must come BEFORE .gap-exiting so exiting wins via specificity+order */
|
|
4510
|
+
.lyrics-gap.active .main-vocal-container {
|
|
4421
4511
|
animation: gap-loop var(--gap-pulse-duration, 4000ms) ease-in-out infinite
|
|
4422
4512
|
alternate;
|
|
4423
4513
|
animation-delay: var(--gap-loop-delay, 0ms);
|
|
4424
|
-
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4516
|
+
/* Jump animation plays during exit — disable transition so animation wins.
|
|
4517
|
+
Placed AFTER .active so it wins when both classes are present briefly. */
|
|
4518
|
+
.lyrics-gap.gap-exiting .main-vocal-container {
|
|
4519
|
+
animation: gap-ended var(--gap-exit-duration, 360ms)
|
|
4520
|
+
cubic-bezier(0.33, 1, 0.68, 1) forwards;
|
|
4521
|
+
transition: none !important;
|
|
4425
4522
|
}
|
|
4426
4523
|
|
|
4427
4524
|
.lyrics-gap .lyrics-syllable {
|
|
@@ -4472,20 +4569,17 @@ AmLyrics.styles = i$3 `
|
|
|
4472
4569
|
background-clip: unset;
|
|
4473
4570
|
}
|
|
4474
4571
|
|
|
4475
|
-
.lyrics-gap.active .lyrics-syllable.highlight,
|
|
4476
4572
|
.lyrics-gap.active .lyrics-syllable.finished,
|
|
4477
|
-
.lyrics-gap.gap-exiting .lyrics-syllable,
|
|
4478
|
-
.lyrics-gap:not(.active).post-active-line
|
|
4479
|
-
|
|
4573
|
+
.lyrics-gap.gap-exiting .lyrics-syllable.finished,
|
|
4574
|
+
.lyrics-gap:not(.active):not(.gap-exiting).post-active-line
|
|
4575
|
+
.lyrics-syllable,
|
|
4576
|
+
.lyrics-gap:not(.active):not(.gap-exiting).lyrics-activest
|
|
4577
|
+
.lyrics-syllable {
|
|
4480
4578
|
background-color: var(--lyplus-text-primary);
|
|
4481
4579
|
animation: none !important;
|
|
4482
4580
|
opacity: 1;
|
|
4483
4581
|
}
|
|
4484
4582
|
|
|
4485
|
-
.lyrics-gap.active .lyrics-syllable.finished {
|
|
4486
|
-
animation: none !important;
|
|
4487
|
-
}
|
|
4488
|
-
|
|
4489
4583
|
/* ==========================================================================
|
|
4490
4584
|
METADATA & FOOTER STYLES
|
|
4491
4585
|
========================================================================== */
|
|
@@ -4514,12 +4608,49 @@ AmLyrics.styles = i$3 `
|
|
|
4514
4608
|
align-items: center;
|
|
4515
4609
|
flex-wrap: wrap;
|
|
4516
4610
|
text-align: left;
|
|
4517
|
-
font-size:
|
|
4518
|
-
color: rgba(255, 255, 255, 0.
|
|
4519
|
-
padding:
|
|
4520
|
-
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
4611
|
+
font-size: 1.2em;
|
|
4612
|
+
color: rgba(255, 255, 255, 0.6);
|
|
4613
|
+
padding: 20px 0 50vh 0;
|
|
4521
4614
|
margin-top: 10px;
|
|
4522
|
-
font-weight:
|
|
4615
|
+
font-weight: 400;
|
|
4616
|
+
opacity: 0.8;
|
|
4617
|
+
transition:
|
|
4618
|
+
opacity 0.3s ease,
|
|
4619
|
+
transform 0.5s cubic-bezier(0.41, 0, 0.12, 0.99),
|
|
4620
|
+
filter 0.3s ease;
|
|
4621
|
+
transform-origin: left;
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
.lyrics-footer.lyrics-line {
|
|
4625
|
+
font-size: 1.2em;
|
|
4626
|
+
padding: 20px var(--lyplus-padding-line) 50vh var(--lyplus-padding-line);
|
|
4627
|
+
cursor: default;
|
|
4628
|
+
}
|
|
4629
|
+
|
|
4630
|
+
.lyrics-footer.active {
|
|
4631
|
+
opacity: 1;
|
|
4632
|
+
color: rgba(255, 255, 255, 0.5); /* Grey instead of primary */
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4635
|
+
.lyrics-footer.scroll-animate {
|
|
4636
|
+
transition: none !important;
|
|
4637
|
+
animation-name: lyrics-scroll;
|
|
4638
|
+
animation-duration: var(--scroll-duration, 280ms);
|
|
4639
|
+
animation-timing-function: cubic-bezier(0.41, 0, 0.12, 0.99);
|
|
4640
|
+
animation-fill-mode: both;
|
|
4641
|
+
animation-delay: var(--lyrics-line-delay, 0ms);
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4644
|
+
.lyrics-container.blur-inactive-enabled:not(.not-focused)
|
|
4645
|
+
.lyrics-footer:not(.active) {
|
|
4646
|
+
filter: blur(var(--lyplus-blur-amount));
|
|
4647
|
+
opacity: 0.5;
|
|
4648
|
+
}
|
|
4649
|
+
|
|
4650
|
+
.lyrics-container.user-scrolling .lyrics-footer {
|
|
4651
|
+
transition: none !important;
|
|
4652
|
+
filter: none !important;
|
|
4653
|
+
opacity: 0.8 !important;
|
|
4523
4654
|
}
|
|
4524
4655
|
|
|
4525
4656
|
.lyrics-footer p {
|
|
@@ -4527,12 +4658,14 @@ AmLyrics.styles = i$3 `
|
|
|
4527
4658
|
}
|
|
4528
4659
|
|
|
4529
4660
|
.lyrics-footer a {
|
|
4530
|
-
color:
|
|
4531
|
-
text-
|
|
4661
|
+
color: var(--lyplus-text-primary); /* Stand out using primary color */
|
|
4662
|
+
text-underline-offset: 2px;
|
|
4663
|
+
opacity: 0.8;
|
|
4664
|
+
transition: opacity 0.2s;
|
|
4532
4665
|
}
|
|
4533
4666
|
|
|
4534
4667
|
.lyrics-footer a:hover {
|
|
4535
|
-
|
|
4668
|
+
opacity: 1;
|
|
4536
4669
|
}
|
|
4537
4670
|
|
|
4538
4671
|
.footer-content {
|
|
@@ -4656,6 +4789,7 @@ AmLyrics.styles = i$3 `
|
|
|
4656
4789
|
|
|
4657
4790
|
.lyrics-romanization-container.rtl-text {
|
|
4658
4791
|
direction: rtl !important;
|
|
4792
|
+
text-align: right;
|
|
4659
4793
|
}
|
|
4660
4794
|
|
|
4661
4795
|
.lyrics-romanization-container .lyrics-syllable {
|
|
@@ -4869,23 +5003,22 @@ AmLyrics.styles = i$3 `
|
|
|
4869
5003
|
/* Gap dot animations */
|
|
4870
5004
|
@keyframes gap-loop {
|
|
4871
5005
|
from {
|
|
4872
|
-
transform: scale(1.12);
|
|
5006
|
+
transform: translateY(-25%) scale(1.12);
|
|
4873
5007
|
}
|
|
4874
5008
|
to {
|
|
4875
|
-
transform: scale(var(--gap-exit-scale, 0.85));
|
|
5009
|
+
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85));
|
|
4876
5010
|
}
|
|
4877
5011
|
}
|
|
4878
5012
|
|
|
4879
5013
|
@keyframes gap-ended {
|
|
4880
5014
|
0% {
|
|
4881
|
-
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85))
|
|
4882
|
-
translateZ(0);
|
|
5015
|
+
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85));
|
|
4883
5016
|
}
|
|
4884
5017
|
35% {
|
|
4885
|
-
transform: translateY(-
|
|
5018
|
+
transform: translateY(-25%) scale(1.2);
|
|
4886
5019
|
}
|
|
4887
5020
|
100% {
|
|
4888
|
-
transform: translateY(-25%) scale(0)
|
|
5021
|
+
transform: translateY(-25%) scale(0);
|
|
4889
5022
|
}
|
|
4890
5023
|
}
|
|
4891
5024
|
|
|
@@ -4902,17 +5035,18 @@ AmLyrics.styles = i$3 `
|
|
|
4902
5035
|
reflow in between) to reliably restart the animation each time */
|
|
4903
5036
|
@keyframes lyrics-scroll {
|
|
4904
5037
|
from {
|
|
4905
|
-
transform:
|
|
5038
|
+
transform: translate3d(0, var(--scroll-delta), 0);
|
|
4906
5039
|
}
|
|
4907
5040
|
to {
|
|
4908
|
-
transform:
|
|
5041
|
+
transform: translate3d(0, 0, 0);
|
|
4909
5042
|
}
|
|
4910
5043
|
}
|
|
4911
5044
|
|
|
4912
|
-
/* Character grow animation
|
|
5045
|
+
/* Character grow animation — translate3d+scale3d for smooth transform,
|
|
5046
|
+
drop-shadow for glow (text-shadow doesn't work with background-clip:text) */
|
|
4913
5047
|
@keyframes grow-dynamic {
|
|
4914
5048
|
0% {
|
|
4915
|
-
transform:
|
|
5049
|
+
transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
|
|
4916
5050
|
filter: drop-shadow(
|
|
4917
5051
|
0 0 0
|
|
4918
5052
|
color-mix(in srgb, var(--lyplus-lyrics-palette), transparent 100%)
|
|
@@ -4920,27 +5054,12 @@ AmLyrics.styles = i$3 `
|
|
|
4920
5054
|
}
|
|
4921
5055
|
25%,
|
|
4922
5056
|
30% {
|
|
4923
|
-
transform:
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
calc(var(--max-scale) * calc(var(--lyplus-font-size-base-grow) / 25)),
|
|
4930
|
-
0,
|
|
4931
|
-
0,
|
|
4932
|
-
0,
|
|
4933
|
-
0,
|
|
4934
|
-
1,
|
|
4935
|
-
0,
|
|
4936
|
-
calc(
|
|
4937
|
-
var(--char-offset-x, 0) *
|
|
4938
|
-
calc(var(--lyplus-font-size-base-grow) / 25)
|
|
4939
|
-
),
|
|
4940
|
-
var(--translate-y-peak, -2),
|
|
4941
|
-
0,
|
|
4942
|
-
1
|
|
4943
|
-
);
|
|
5057
|
+
transform: translate3d(
|
|
5058
|
+
var(--char-offset-x, 0px),
|
|
5059
|
+
var(--translate-y-peak, -2px),
|
|
5060
|
+
0
|
|
5061
|
+
)
|
|
5062
|
+
scale3d(var(--matrix-scale, 1.1), var(--matrix-scale, 1.1), 1);
|
|
4944
5063
|
filter: drop-shadow(
|
|
4945
5064
|
0 0 0.1em
|
|
4946
5065
|
color-mix(
|
|
@@ -4950,8 +5069,10 @@ AmLyrics.styles = i$3 `
|
|
|
4950
5069
|
)
|
|
4951
5070
|
);
|
|
4952
5071
|
}
|
|
5072
|
+
75%,
|
|
4953
5073
|
100% {
|
|
4954
|
-
transform:
|
|
5074
|
+
transform: translate3d(0, var(--char-rise-y, -1.12px), 0)
|
|
5075
|
+
scale3d(1, 1, 1);
|
|
4955
5076
|
filter: drop-shadow(
|
|
4956
5077
|
0 0 0
|
|
4957
5078
|
color-mix(in srgb, var(--lyplus-lyrics-palette), transparent 100%)
|
|
@@ -5083,15 +5204,15 @@ __decorate([
|
|
|
5083
5204
|
__decorate([
|
|
5084
5205
|
n({ type: String, attribute: 'song-album' })
|
|
5085
5206
|
], AmLyrics.prototype, "songAlbum", void 0);
|
|
5207
|
+
__decorate([
|
|
5208
|
+
n({ type: String, attribute: 'songwriters' })
|
|
5209
|
+
], AmLyrics.prototype, "songwriters", void 0);
|
|
5086
5210
|
__decorate([
|
|
5087
5211
|
n({ type: Number, attribute: 'song-duration' })
|
|
5088
5212
|
], AmLyrics.prototype, "songDurationMs", void 0);
|
|
5089
5213
|
__decorate([
|
|
5090
5214
|
n({ type: String, attribute: 'highlight-color' })
|
|
5091
5215
|
], AmLyrics.prototype, "highlightColor", void 0);
|
|
5092
|
-
__decorate([
|
|
5093
|
-
n({ type: String, attribute: 'hover-background-color' })
|
|
5094
|
-
], AmLyrics.prototype, "hoverBackgroundColor", void 0);
|
|
5095
5216
|
__decorate([
|
|
5096
5217
|
n({ type: String, attribute: 'font-family' })
|
|
5097
5218
|
], AmLyrics.prototype, "fontFamily", void 0);
|