@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/react.js
CHANGED
|
@@ -322,7 +322,7 @@ class GoogleService {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
const VERSION = '1.
|
|
325
|
+
const VERSION = '1.4.1';
|
|
326
326
|
const INSTRUMENTAL_THRESHOLD_MS = 7000; // Show dots for gaps >= 7s
|
|
327
327
|
const FETCH_TIMEOUT_MS = 8000; // Timeout for all lyrics fetch requests
|
|
328
328
|
const SEEK_THRESHOLD_MS = 500;
|
|
@@ -345,32 +345,17 @@ function fetchWithTimeout(url, options = {}, timeoutMs = FETCH_TIMEOUT_MS) {
|
|
|
345
345
|
}
|
|
346
346
|
const KPOE_SERVERS = [
|
|
347
347
|
'https://lyricsplus.binimum.org',
|
|
348
|
-
'https://lyricsplus.atomix.one',
|
|
349
348
|
'https://lyricsplus-seven.vercel.app',
|
|
350
349
|
'https://lyricsplus.prjktla.workers.dev',
|
|
351
350
|
'https://lyrics-plus-backend.vercel.app',
|
|
352
351
|
];
|
|
353
352
|
const DEFAULT_KPOE_SOURCE_ORDER = 'apple,lyricsplus,musixmatch,spotify,qq,deezer,musixmatch-word';
|
|
354
|
-
const TIDAL_SERVERS = [
|
|
355
|
-
'https://arran.monochrome.tf',
|
|
356
|
-
'https://api.monochrome.tf/',
|
|
357
|
-
'https://triton.squid.wtf',
|
|
358
|
-
'https://wolf.qqdl.site',
|
|
359
|
-
'https://maus.qqdl.site',
|
|
360
|
-
'https://vogel.qqdl.site',
|
|
361
|
-
'https://katze.qqdl.site',
|
|
362
|
-
'https://hund.qqdl.site',
|
|
363
|
-
'https://tidal.kinoplus.online',
|
|
364
|
-
'https://hifi-one.spotisaver.net',
|
|
365
|
-
'https://hifi-two.spotisaver.net',
|
|
366
|
-
];
|
|
367
353
|
const GENIUS_WORKER_URL = 'https://fetch-genius.samidy.workers.dev/';
|
|
368
354
|
let AmLyrics$1 = class AmLyrics extends i {
|
|
369
355
|
constructor() {
|
|
370
356
|
super(...arguments);
|
|
371
357
|
this.downloadFormat = 'auto';
|
|
372
358
|
this.highlightColor = '#ffffff';
|
|
373
|
-
this.hoverBackgroundColor = 'rgba(255, 255, 255, 0.13)';
|
|
374
359
|
this.autoScroll = true;
|
|
375
360
|
this.interpolate = true;
|
|
376
361
|
this.showRomanization = false;
|
|
@@ -415,6 +400,10 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
415
400
|
// Syllable animation tracking
|
|
416
401
|
this.lastActiveIndex = 0;
|
|
417
402
|
this.visibleLineIds = new Set();
|
|
403
|
+
// Cached element tracking to avoid repeated querySelectorAll calls
|
|
404
|
+
this.preActiveLineElements = [];
|
|
405
|
+
this.positionedLineElements = [];
|
|
406
|
+
this.activeGapLineElements = [];
|
|
418
407
|
// Bound handler references for proper event listener removal
|
|
419
408
|
this._boundHandleUserScroll = this.handleUserScroll.bind(this);
|
|
420
409
|
this._boundAnimateProgress = this.animateProgress.bind(this);
|
|
@@ -487,6 +476,31 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
487
476
|
}
|
|
488
477
|
set currentTime(value) {
|
|
489
478
|
const oldValue = this._currentTime;
|
|
479
|
+
// If the new time is significantly smaller than the old time (e.g. song looped)
|
|
480
|
+
if (value < oldValue && oldValue - value > 1000 && this.lyrics) {
|
|
481
|
+
this.activeLineIndices = [];
|
|
482
|
+
this.activeMainWordIndices.clear();
|
|
483
|
+
this.activeBackgroundWordIndices.clear();
|
|
484
|
+
this.mainWordProgress.clear();
|
|
485
|
+
this.backgroundWordProgress.clear();
|
|
486
|
+
this.mainWordAnimations.clear();
|
|
487
|
+
this.backgroundWordAnimations.clear();
|
|
488
|
+
this.preActiveLineElements = [];
|
|
489
|
+
this.positionedLineElements = [];
|
|
490
|
+
this.activeGapLineElements = [];
|
|
491
|
+
// Stop all running animations and clear highlights immediately
|
|
492
|
+
if (this.lyricsContainer) {
|
|
493
|
+
const activeLines = this.lyricsContainer.querySelectorAll('.lyrics-line.active, .lyrics-line.pre-active');
|
|
494
|
+
activeLines.forEach(line => {
|
|
495
|
+
line.classList.remove('active', 'pre-active');
|
|
496
|
+
AmLyrics.resetSyllables(line);
|
|
497
|
+
});
|
|
498
|
+
const activeGaps = this.lyricsContainer.querySelectorAll('.lyrics-gap.active, .lyrics-gap.gap-exiting');
|
|
499
|
+
activeGaps.forEach(gap => gap.classList.remove('active', 'gap-exiting'));
|
|
500
|
+
// Reset gap cache since we manually messed with the elements
|
|
501
|
+
this.gapElementCache.clear();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
490
504
|
this._currentTime = value;
|
|
491
505
|
if (oldValue !== value && this.lyrics) {
|
|
492
506
|
this._onTimeChanged(oldValue, value);
|
|
@@ -548,6 +562,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
548
562
|
this.lyricsContainer.removeEventListener('wheel', this._boundHandleUserScroll);
|
|
549
563
|
this.lyricsContainer.removeEventListener('touchmove', this._boundHandleUserScroll);
|
|
550
564
|
}
|
|
565
|
+
this.preActiveLineElements = [];
|
|
566
|
+
this.positionedLineElements = [];
|
|
567
|
+
this.activeGapLineElements = [];
|
|
551
568
|
}
|
|
552
569
|
async fetchLyrics() {
|
|
553
570
|
// Cancel any in-flight fetch to prevent stale results from racing
|
|
@@ -582,16 +599,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
582
599
|
}
|
|
583
600
|
}
|
|
584
601
|
if (collectedSources.length === 0 && resolvedMetadata?.metadata) {
|
|
585
|
-
|
|
586
|
-
if (tidalResult && tidalResult.lines.length > 0) {
|
|
587
|
-
collectedSources.push({
|
|
588
|
-
lines: tidalResult.lines,
|
|
589
|
-
source: 'Tidal',
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
// Fallback: LRCLIB
|
|
594
|
-
if (collectedSources.length === 0 && resolvedMetadata?.metadata) {
|
|
602
|
+
// Fallback: LRCLIB
|
|
595
603
|
const lrclibResult = await AmLyrics.fetchLyricsFromLrclib(resolvedMetadata.metadata);
|
|
596
604
|
if (lrclibResult && lrclibResult.lines.length > 0) {
|
|
597
605
|
collectedSources.push({
|
|
@@ -611,15 +619,17 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
611
619
|
}
|
|
612
620
|
this.hasFetchedAllProviders =
|
|
613
621
|
collectedSources.length === 0 ||
|
|
614
|
-
collectedSources.some(s => s.source === 'LRCLIB' ||
|
|
615
|
-
s.source === 'Tidal' ||
|
|
616
|
-
s.source === 'Genius');
|
|
622
|
+
collectedSources.some(s => s.source === 'LRCLIB' || s.source === 'Genius');
|
|
617
623
|
this._updateFooter();
|
|
618
624
|
if (collectedSources.length > 0) {
|
|
619
625
|
this.availableSources = AmLyrics.mergeAndSortSources(collectedSources);
|
|
620
626
|
this.currentSourceIndex = 0;
|
|
621
|
-
|
|
622
|
-
this.
|
|
627
|
+
const sourceResult = this.availableSources[0];
|
|
628
|
+
this.lyrics = sourceResult.lines;
|
|
629
|
+
this.lyricsSource = sourceResult.source;
|
|
630
|
+
if (sourceResult.songwriters) {
|
|
631
|
+
this.songwriters = sourceResult.songwriters;
|
|
632
|
+
}
|
|
623
633
|
await this.onLyricsLoaded();
|
|
624
634
|
return;
|
|
625
635
|
}
|
|
@@ -641,6 +651,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
641
651
|
this.backgroundWordProgress.clear();
|
|
642
652
|
this.mainWordAnimations.clear();
|
|
643
653
|
this.backgroundWordAnimations.clear();
|
|
654
|
+
this.preActiveLineElements = [];
|
|
655
|
+
this.positionedLineElements = [];
|
|
656
|
+
this.activeGapLineElements = [];
|
|
644
657
|
if (this.lyricsContainer) {
|
|
645
658
|
this.isProgrammaticScroll = true;
|
|
646
659
|
this.lyricsContainer.scrollTop = 0;
|
|
@@ -670,36 +683,30 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
670
683
|
return 2;
|
|
671
684
|
if (lower.includes('musixmatch') && hasWordSync)
|
|
672
685
|
return 3;
|
|
673
|
-
if (lower.includes('tidal') && hasWordSync)
|
|
674
|
-
return 4;
|
|
675
686
|
if (lower.includes('lrclib') && hasWordSync)
|
|
676
|
-
return
|
|
687
|
+
return 4;
|
|
677
688
|
if (hasWordSync)
|
|
678
|
-
return
|
|
689
|
+
return 5;
|
|
679
690
|
if (lower.includes('apple') && !hasWordSync && !isUnsynced)
|
|
680
|
-
return
|
|
691
|
+
return 6;
|
|
681
692
|
if (isQQ && !hasWordSync && !isUnsynced)
|
|
682
|
-
return
|
|
693
|
+
return 7;
|
|
683
694
|
if (lower.includes('musixmatch') && !hasWordSync && !isUnsynced)
|
|
684
|
-
return
|
|
685
|
-
if (lower.includes('tidal') && !hasWordSync && !isUnsynced)
|
|
686
|
-
return 10;
|
|
695
|
+
return 8;
|
|
687
696
|
if (lower.includes('lrclib') && !hasWordSync && !isUnsynced)
|
|
688
|
-
return
|
|
697
|
+
return 9;
|
|
689
698
|
if (!hasWordSync && !isUnsynced)
|
|
690
|
-
return
|
|
699
|
+
return 10;
|
|
691
700
|
if (lower.includes('apple') && isUnsynced)
|
|
692
|
-
return
|
|
701
|
+
return 11;
|
|
693
702
|
if (isQQ && isUnsynced)
|
|
694
|
-
return
|
|
703
|
+
return 12;
|
|
695
704
|
if (lower.includes('musixmatch') && isUnsynced)
|
|
696
|
-
return
|
|
697
|
-
if (lower.includes('tidal') && isUnsynced)
|
|
698
|
-
return 16;
|
|
705
|
+
return 13;
|
|
699
706
|
if (lower.includes('lrclib') && isUnsynced)
|
|
700
|
-
return
|
|
707
|
+
return 14;
|
|
701
708
|
if (lower.includes('genius'))
|
|
702
|
-
return
|
|
709
|
+
return 15;
|
|
703
710
|
return 20;
|
|
704
711
|
}
|
|
705
712
|
static mergeAndSortSources(collectedSources) {
|
|
@@ -730,13 +737,6 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
730
737
|
const resolvedMetadata = await this.resolveSongMetadata();
|
|
731
738
|
if (resolvedMetadata?.metadata) {
|
|
732
739
|
const newSources = [];
|
|
733
|
-
// Try Tidal if not fetched
|
|
734
|
-
if (!this.availableSources.some(s => s.source.toLowerCase().includes('tidal'))) {
|
|
735
|
-
const tidalResult = await AmLyrics.fetchLyricsFromTidal(resolvedMetadata.metadata, resolvedMetadata.catalogIsrc);
|
|
736
|
-
if (tidalResult && tidalResult.lines.length > 0) {
|
|
737
|
-
newSources.push({ lines: tidalResult.lines, source: 'Tidal' });
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
740
|
// Try LRCLIB if not fetched
|
|
741
741
|
if (!this.availableSources.some(s => s.source.toLowerCase().includes('lrclib'))) {
|
|
742
742
|
const lrclibResult = await AmLyrics.fetchLyricsFromLrclib(resolvedMetadata.metadata);
|
|
@@ -771,8 +771,12 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
771
771
|
if (this.availableSources.length > 1) {
|
|
772
772
|
this.currentSourceIndex =
|
|
773
773
|
(this.currentSourceIndex + 1) % this.availableSources.length;
|
|
774
|
-
|
|
775
|
-
this.
|
|
774
|
+
const sourceResult = this.availableSources[this.currentSourceIndex];
|
|
775
|
+
this.lyrics = sourceResult.lines;
|
|
776
|
+
this.lyricsSource = sourceResult.source;
|
|
777
|
+
if (sourceResult.songwriters) {
|
|
778
|
+
this.songwriters = sourceResult.songwriters;
|
|
779
|
+
}
|
|
776
780
|
await this.onLyricsLoaded();
|
|
777
781
|
}
|
|
778
782
|
}
|
|
@@ -781,6 +785,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
781
785
|
title: this.songTitle?.trim() ?? '',
|
|
782
786
|
artist: this.songArtist?.trim() ?? '',
|
|
783
787
|
album: this.songAlbum?.trim() || undefined,
|
|
788
|
+
songwriters: this.songwriters?.trim() || undefined,
|
|
784
789
|
durationMs: undefined,
|
|
785
790
|
};
|
|
786
791
|
if (typeof this.songDurationMs === 'number' && this.songDurationMs > 0) {
|
|
@@ -820,6 +825,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
820
825
|
if (!metadata.album && catalogResult.album) {
|
|
821
826
|
metadata.album = catalogResult.album;
|
|
822
827
|
}
|
|
828
|
+
if (!metadata.songwriters && catalogResult.songwriters) {
|
|
829
|
+
metadata.songwriters = catalogResult.songwriters;
|
|
830
|
+
}
|
|
823
831
|
if (metadata.durationMs == null &&
|
|
824
832
|
typeof catalogResult.durationMs === 'number' &&
|
|
825
833
|
catalogResult.durationMs > 0) {
|
|
@@ -1010,9 +1018,13 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1010
1018
|
const ttmlRes = await fetchWithTimeout(result.lyricsUrl);
|
|
1011
1019
|
if (ttmlRes.ok) {
|
|
1012
1020
|
const ttmlText = await ttmlRes.text();
|
|
1013
|
-
const
|
|
1014
|
-
if (
|
|
1015
|
-
allResults.push({
|
|
1021
|
+
const parseResult = AmLyrics.parseTTML(ttmlText);
|
|
1022
|
+
if (parseResult && parseResult.lines.length > 0) {
|
|
1023
|
+
allResults.push({
|
|
1024
|
+
lines: parseResult.lines,
|
|
1025
|
+
source: 'BiniLyrics',
|
|
1026
|
+
songwriters: parseResult.songwriters,
|
|
1027
|
+
});
|
|
1016
1028
|
return allResults;
|
|
1017
1029
|
}
|
|
1018
1030
|
}
|
|
@@ -1044,11 +1056,12 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1044
1056
|
const ttmlRes = await fetchWithTimeout(result.lyricsUrl);
|
|
1045
1057
|
if (ttmlRes.ok) {
|
|
1046
1058
|
const ttmlText = await ttmlRes.text();
|
|
1047
|
-
const
|
|
1048
|
-
if (
|
|
1059
|
+
const parseResult = AmLyrics.parseTTML(ttmlText);
|
|
1060
|
+
if (parseResult && parseResult.lines.length > 0) {
|
|
1049
1061
|
allResults.push({
|
|
1050
|
-
lines,
|
|
1062
|
+
lines: parseResult.lines,
|
|
1051
1063
|
source: 'BiniLyrics',
|
|
1064
|
+
songwriters: parseResult.songwriters,
|
|
1052
1065
|
});
|
|
1053
1066
|
return allResults;
|
|
1054
1067
|
}
|
|
@@ -1181,77 +1194,6 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1181
1194
|
}
|
|
1182
1195
|
return lines;
|
|
1183
1196
|
}
|
|
1184
|
-
/**
|
|
1185
|
-
* Fetch lyrics from Tidal API.
|
|
1186
|
-
* Picks 2 random servers, tries search + lyrics on each.
|
|
1187
|
-
*/
|
|
1188
|
-
static async fetchLyricsFromTidal(metadata, isrc) {
|
|
1189
|
-
const title = metadata.title?.trim();
|
|
1190
|
-
const artist = metadata.artist?.trim();
|
|
1191
|
-
if (!title || !artist)
|
|
1192
|
-
return null;
|
|
1193
|
-
// Pick 3 random unique servers for better reliability
|
|
1194
|
-
const shuffled = [...TIDAL_SERVERS].sort(() => Math.random() - 0.5);
|
|
1195
|
-
const serversToTry = shuffled.slice(0, 3);
|
|
1196
|
-
for (const base of serversToTry) {
|
|
1197
|
-
try {
|
|
1198
|
-
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
|
|
1199
|
-
// Step 1: Search for the track
|
|
1200
|
-
const searchQuery = `${title} ${artist}`;
|
|
1201
|
-
const searchParams = new URLSearchParams({ s: searchQuery });
|
|
1202
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1203
|
-
const searchResponse = await fetchWithTimeout(`${normalizedBase}/search/?${searchParams.toString()}`);
|
|
1204
|
-
if (!searchResponse.ok) {
|
|
1205
|
-
// eslint-disable-next-line no-continue
|
|
1206
|
-
continue;
|
|
1207
|
-
}
|
|
1208
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1209
|
-
const searchData = await searchResponse.json();
|
|
1210
|
-
const items = searchData?.data?.items;
|
|
1211
|
-
if (!Array.isArray(items) || items.length === 0) {
|
|
1212
|
-
// eslint-disable-next-line no-continue
|
|
1213
|
-
continue;
|
|
1214
|
-
}
|
|
1215
|
-
// Find best match: prefer ISRC match, then first result
|
|
1216
|
-
let bestTrack = items[0];
|
|
1217
|
-
if (isrc) {
|
|
1218
|
-
const isrcMatch = items.find((item) => item.isrc && item.isrc.toLowerCase() === isrc.toLowerCase());
|
|
1219
|
-
if (isrcMatch) {
|
|
1220
|
-
bestTrack = isrcMatch;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
const trackId = bestTrack?.id;
|
|
1224
|
-
if (!trackId) {
|
|
1225
|
-
// eslint-disable-next-line no-continue
|
|
1226
|
-
continue;
|
|
1227
|
-
}
|
|
1228
|
-
// Step 2: Fetch lyrics
|
|
1229
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1230
|
-
const lyricsResponse = await fetchWithTimeout(`${normalizedBase}/lyrics/?id=${trackId}`);
|
|
1231
|
-
if (!lyricsResponse.ok) {
|
|
1232
|
-
// eslint-disable-next-line no-continue
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1236
|
-
const lyricsData = await lyricsResponse.json();
|
|
1237
|
-
const subtitles = lyricsData?.lyrics?.subtitles;
|
|
1238
|
-
if (subtitles && typeof subtitles === 'string') {
|
|
1239
|
-
const lines = AmLyrics.parseLrcSubtitles(subtitles);
|
|
1240
|
-
if (lines.length > 0) {
|
|
1241
|
-
const provider = lyricsData?.lyrics?.lyricsProvider || 'Tidal';
|
|
1242
|
-
return {
|
|
1243
|
-
lines,
|
|
1244
|
-
source: `Tidal (${provider})`,
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
catch {
|
|
1250
|
-
// Try next server
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
return null;
|
|
1254
|
-
}
|
|
1255
1197
|
/**
|
|
1256
1198
|
* Fetch lyrics from LRCLIB.
|
|
1257
1199
|
* Uses search endpoint, prefers synced lyrics.
|
|
@@ -1434,6 +1376,19 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1434
1376
|
agentMap[id] = type;
|
|
1435
1377
|
}
|
|
1436
1378
|
}
|
|
1379
|
+
let songwriters;
|
|
1380
|
+
const songwritersNodes = doc.getElementsByTagName('songwriter');
|
|
1381
|
+
if (songwritersNodes.length > 0) {
|
|
1382
|
+
const names = [];
|
|
1383
|
+
for (let i = 0; i < songwritersNodes.length; i += 1) {
|
|
1384
|
+
if (songwritersNodes[i].textContent) {
|
|
1385
|
+
names.push(songwritersNodes[i].textContent);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (names.length > 0) {
|
|
1389
|
+
songwriters = names.join(', ');
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1437
1392
|
const translationNodes = doc.getElementsByTagName('translation');
|
|
1438
1393
|
for (let i = 0; i < translationNodes.length; i += 1) {
|
|
1439
1394
|
const texts = translationNodes[i].getElementsByTagName('text');
|
|
@@ -1550,7 +1505,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1550
1505
|
text: bgText,
|
|
1551
1506
|
timestamp: timeToMs(bgSpan.getAttribute('begin')),
|
|
1552
1507
|
endtime: timeToMs(bgSpan.getAttribute('end')),
|
|
1553
|
-
part:
|
|
1508
|
+
part: !/\s$/.test(bgText),
|
|
1554
1509
|
});
|
|
1555
1510
|
}
|
|
1556
1511
|
// eslint-disable-next-line no-continue
|
|
@@ -1573,7 +1528,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1573
1528
|
text,
|
|
1574
1529
|
timestamp: timeToMs(span.getAttribute('begin')),
|
|
1575
1530
|
endtime: timeToMs(span.getAttribute('end')),
|
|
1576
|
-
part:
|
|
1531
|
+
part: !/\s$/.test(text),
|
|
1577
1532
|
});
|
|
1578
1533
|
}
|
|
1579
1534
|
}
|
|
@@ -1659,7 +1614,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1659
1614
|
oppositeTurn: alignment === 'end',
|
|
1660
1615
|
});
|
|
1661
1616
|
}
|
|
1662
|
-
return lines;
|
|
1617
|
+
return { lines, songwriters };
|
|
1663
1618
|
}
|
|
1664
1619
|
catch (e) {
|
|
1665
1620
|
// eslint-disable-next-line no-console
|
|
@@ -1824,7 +1779,10 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1824
1779
|
if (!newActiveLines.includes(lineIndex)) {
|
|
1825
1780
|
const lineElement = this._getLineElement(lineIndex);
|
|
1826
1781
|
if (lineElement) {
|
|
1827
|
-
lineElement.classList.remove('active');
|
|
1782
|
+
lineElement.classList.remove('active', 'pre-active');
|
|
1783
|
+
const preIdx = this.preActiveLineElements.indexOf(lineElement);
|
|
1784
|
+
if (preIdx !== -1)
|
|
1785
|
+
this.preActiveLineElements.splice(preIdx, 1);
|
|
1828
1786
|
AmLyrics.resetSyllables(lineElement);
|
|
1829
1787
|
}
|
|
1830
1788
|
}
|
|
@@ -1836,6 +1794,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1836
1794
|
if (lineElement) {
|
|
1837
1795
|
lineElement.classList.add('active');
|
|
1838
1796
|
lineElement.classList.remove('pre-active');
|
|
1797
|
+
const preIdx = this.preActiveLineElements.indexOf(lineElement);
|
|
1798
|
+
if (preIdx !== -1)
|
|
1799
|
+
this.preActiveLineElements.splice(preIdx, 1);
|
|
1839
1800
|
}
|
|
1840
1801
|
}
|
|
1841
1802
|
}
|
|
@@ -1855,10 +1816,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1855
1816
|
}
|
|
1856
1817
|
}
|
|
1857
1818
|
// Also update syllables in active gap lines (breathing dots)
|
|
1858
|
-
const
|
|
1859
|
-
activeGaps.forEach(gapLine => {
|
|
1819
|
+
for (const gapLine of this.activeGapLineElements) {
|
|
1860
1820
|
AmLyrics.updateSyllablesForLine(gapLine, newTime);
|
|
1861
|
-
}
|
|
1821
|
+
}
|
|
1862
1822
|
// Imperatively manage gap active state
|
|
1863
1823
|
if (this.gapElementCache.size > 0) {
|
|
1864
1824
|
for (const [, gap] of this.gapElementCache) {
|
|
@@ -1869,9 +1829,21 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1869
1829
|
const isExiting = gap.classList.contains('gap-exiting');
|
|
1870
1830
|
const exitLeadMs = GAP_EXIT_LEAD_MS;
|
|
1871
1831
|
const shouldStartExiting = isActive && !isExiting && newTime >= gapEndTime - exitLeadMs;
|
|
1872
|
-
if (shouldBeActive && !isActive && !isExiting) {
|
|
1832
|
+
if (shouldBeActive && (!isActive || isSeek) && !isExiting) {
|
|
1873
1833
|
gap.classList.remove('gap-exiting');
|
|
1834
|
+
if (isSeek && isActive) {
|
|
1835
|
+
gap.classList.remove('active');
|
|
1836
|
+
// eslint-disable-next-line no-void
|
|
1837
|
+
void gap.offsetWidth; // Force reflow
|
|
1838
|
+
}
|
|
1839
|
+
const gapDuration = gapEndTime - gapStartTime;
|
|
1840
|
+
const baseLoopDelay = AmLyrics.getGapLoopDelay(gapDuration);
|
|
1841
|
+
const totalDelay = baseLoopDelay + (newTime - gapStartTime);
|
|
1842
|
+
gap.style.setProperty('--gap-loop-delay', `-${totalDelay}ms`);
|
|
1874
1843
|
gap.classList.add('active');
|
|
1844
|
+
if (!this.activeGapLineElements.includes(gap)) {
|
|
1845
|
+
this.activeGapLineElements.push(gap);
|
|
1846
|
+
}
|
|
1875
1847
|
const dotSyllables = gap.querySelectorAll('.lyrics-syllable');
|
|
1876
1848
|
dotSyllables.forEach(dot => {
|
|
1877
1849
|
const dotStart = parseFloat(dot.getAttribute('data-start-time') || '0');
|
|
@@ -1879,24 +1851,34 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1879
1851
|
if (newTime > dotEnd) {
|
|
1880
1852
|
dot.classList.add('finished');
|
|
1881
1853
|
if (!dot.classList.contains('highlight')) {
|
|
1882
|
-
AmLyrics.updateSyllableAnimation(dot);
|
|
1854
|
+
AmLyrics.updateSyllableAnimation(dot, newTime - dotStart);
|
|
1883
1855
|
}
|
|
1884
1856
|
}
|
|
1885
1857
|
else if (newTime >= dotStart && newTime <= dotEnd) {
|
|
1886
|
-
AmLyrics.updateSyllableAnimation(dot);
|
|
1858
|
+
AmLyrics.updateSyllableAnimation(dot, newTime - dotStart);
|
|
1887
1859
|
}
|
|
1888
1860
|
});
|
|
1889
1861
|
}
|
|
1890
1862
|
else if (shouldStartExiting) {
|
|
1891
|
-
gap
|
|
1863
|
+
// Cancel gap-loop first, force reflow, then start gap-ended
|
|
1864
|
+
// so the browser sees a clean animation swap
|
|
1892
1865
|
gap.classList.remove('active');
|
|
1866
|
+
// eslint-disable-next-line no-void
|
|
1867
|
+
void gap.offsetWidth;
|
|
1868
|
+
gap.classList.add('gap-exiting');
|
|
1869
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1870
|
+
if (gapIdx !== -1)
|
|
1871
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1893
1872
|
setTimeout(() => {
|
|
1894
1873
|
gap.classList.remove('gap-exiting');
|
|
1895
1874
|
}, GAP_EXIT_LEAD_MS);
|
|
1896
1875
|
}
|
|
1897
|
-
else if (
|
|
1876
|
+
else if (!shouldBeActive && (isActive || isExiting)) {
|
|
1898
1877
|
gap.classList.remove('active');
|
|
1899
1878
|
gap.classList.remove('gap-exiting');
|
|
1879
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1880
|
+
if (gapIdx !== -1)
|
|
1881
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1900
1882
|
}
|
|
1901
1883
|
else if (isExiting && newTime < gapEndTime - exitLeadMs) {
|
|
1902
1884
|
gap.classList.remove('gap-exiting');
|
|
@@ -1914,20 +1896,41 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1914
1896
|
const isExiting = gap.classList.contains('gap-exiting');
|
|
1915
1897
|
const exitLeadMs = GAP_EXIT_LEAD_MS;
|
|
1916
1898
|
const shouldStartExiting = isActive && !isExiting && newTime >= gapEndTime - exitLeadMs;
|
|
1917
|
-
if (shouldBeActive && !isActive && !isExiting) {
|
|
1899
|
+
if (shouldBeActive && (!isActive || isSeek) && !isExiting) {
|
|
1918
1900
|
gap.classList.remove('gap-exiting');
|
|
1901
|
+
if (isSeek && isActive) {
|
|
1902
|
+
gap.classList.remove('active');
|
|
1903
|
+
// eslint-disable-next-line no-void
|
|
1904
|
+
void gap.offsetWidth; // Force reflow
|
|
1905
|
+
}
|
|
1906
|
+
const gapDuration = gapEndTime - gapStartTime;
|
|
1907
|
+
const baseLoopDelay = AmLyrics.getGapLoopDelay(gapDuration);
|
|
1908
|
+
const totalDelay = baseLoopDelay + (newTime - gapStartTime);
|
|
1909
|
+
gap.style.setProperty('--gap-loop-delay', `-${totalDelay}ms`);
|
|
1919
1910
|
gap.classList.add('active');
|
|
1911
|
+
if (!this.activeGapLineElements.includes(gap)) {
|
|
1912
|
+
this.activeGapLineElements.push(gap);
|
|
1913
|
+
}
|
|
1920
1914
|
}
|
|
1921
1915
|
else if (shouldStartExiting) {
|
|
1922
|
-
gap
|
|
1916
|
+
// Cancel gap-loop first, force reflow, then start gap-ended
|
|
1923
1917
|
gap.classList.remove('active');
|
|
1918
|
+
// eslint-disable-next-line no-void
|
|
1919
|
+
void gap.offsetWidth;
|
|
1920
|
+
gap.classList.add('gap-exiting');
|
|
1921
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1922
|
+
if (gapIdx !== -1)
|
|
1923
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1924
1924
|
setTimeout(() => {
|
|
1925
1925
|
gap.classList.remove('gap-exiting');
|
|
1926
1926
|
}, GAP_EXIT_LEAD_MS);
|
|
1927
1927
|
}
|
|
1928
|
-
else if (
|
|
1928
|
+
else if (!shouldBeActive && (isActive || isExiting)) {
|
|
1929
1929
|
gap.classList.remove('active');
|
|
1930
1930
|
gap.classList.remove('gap-exiting');
|
|
1931
|
+
const gapIdx = this.activeGapLineElements.indexOf(gap);
|
|
1932
|
+
if (gapIdx !== -1)
|
|
1933
|
+
this.activeGapLineElements.splice(gapIdx, 1);
|
|
1931
1934
|
}
|
|
1932
1935
|
else if (isExiting && newTime < gapEndTime - exitLeadMs) {
|
|
1933
1936
|
gap.classList.remove('gap-exiting');
|
|
@@ -1942,6 +1945,25 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1942
1945
|
else if (this.lastInstrumentalIndex !== null) {
|
|
1943
1946
|
this.lastInstrumentalIndex = null;
|
|
1944
1947
|
}
|
|
1948
|
+
// Check footer active state
|
|
1949
|
+
const lastLyric = this.lyrics && this.lyrics.length > 0
|
|
1950
|
+
? this.lyrics[this.lyrics.length - 1]
|
|
1951
|
+
: null;
|
|
1952
|
+
const footer = this.lyricsContainer.querySelector('.lyrics-footer');
|
|
1953
|
+
if (footer && lastLyric && lastLyric.endtime > 0) {
|
|
1954
|
+
const isFooterActive = newTime > lastLyric.endtime + 200; // Snappier 200ms buffer
|
|
1955
|
+
if (isFooterActive && !footer.classList.contains('active')) {
|
|
1956
|
+
footer.classList.add('active');
|
|
1957
|
+
if (this.autoScroll &&
|
|
1958
|
+
!this.isUserScrolling &&
|
|
1959
|
+
!this.isClickSeeking) {
|
|
1960
|
+
this.focusLine(footer);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
else if (!isFooterActive && footer.classList.contains('active')) {
|
|
1964
|
+
footer.classList.remove('active');
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1945
1967
|
// Pre-scroll: scroll to upcoming line ~0.5s before it starts
|
|
1946
1968
|
if (this.autoScroll &&
|
|
1947
1969
|
!this.isUserScrolling &&
|
|
@@ -1964,6 +1986,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1964
1986
|
preActiveLineIndex = i;
|
|
1965
1987
|
if (!isBackToBack) {
|
|
1966
1988
|
nextLineEl.classList.add('pre-active');
|
|
1989
|
+
if (!this.preActiveLineElements.includes(nextLineEl)) {
|
|
1990
|
+
this.preActiveLineElements.push(nextLineEl);
|
|
1991
|
+
}
|
|
1967
1992
|
}
|
|
1968
1993
|
this.clearPreActiveClasses(i);
|
|
1969
1994
|
const slowScrollDuration = Math.max(SCROLL_ANIMATION_DURATION_MS, timeUntilStart);
|
|
@@ -1993,6 +2018,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
1993
2018
|
if (lineEl)
|
|
1994
2019
|
lineEl.classList.add('active');
|
|
1995
2020
|
}
|
|
2021
|
+
// Trigger a faux time-change so that updateSyllablesForLine fires
|
|
2022
|
+
// to setup inline syllable CSS wipe animations for whatever the current time is
|
|
2023
|
+
this._onTimeChanged(0, this.currentTime);
|
|
1996
2024
|
}
|
|
1997
2025
|
}
|
|
1998
2026
|
// Handle duration reset (-1 stops playback and resets currentTime to 0)
|
|
@@ -2005,6 +2033,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2005
2033
|
this.backgroundWordProgress.clear();
|
|
2006
2034
|
this.mainWordAnimations.clear();
|
|
2007
2035
|
this.backgroundWordAnimations.clear();
|
|
2036
|
+
this.preActiveLineElements = [];
|
|
2037
|
+
this.positionedLineElements = [];
|
|
2038
|
+
this.activeGapLineElements = [];
|
|
2008
2039
|
this.setUserScrolling(false);
|
|
2009
2040
|
// Cancel any running animations
|
|
2010
2041
|
if (this.animationFrameId) {
|
|
@@ -2058,7 +2089,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2058
2089
|
const gap = this.lyrics[targetLineIndex].timestamp -
|
|
2059
2090
|
this.lyrics[prevPrimaryIndex].endtime;
|
|
2060
2091
|
if (gap > 200) {
|
|
2061
|
-
scrollDuration = Math.min(Math.max(gap * 0.
|
|
2092
|
+
scrollDuration = Math.min(Math.max(gap * 0.85, SCROLL_ANIMATION_DURATION_MS), 4000);
|
|
2062
2093
|
}
|
|
2063
2094
|
}
|
|
2064
2095
|
this.focusLine(targetLine, forceScroll, scrollDuration);
|
|
@@ -2120,6 +2151,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2120
2151
|
this.cachedLineData = null;
|
|
2121
2152
|
this.lineElementCache.clear();
|
|
2122
2153
|
this.gapElementCache.clear();
|
|
2154
|
+
this.preActiveLineElements = [];
|
|
2155
|
+
this.positionedLineElements = [];
|
|
2156
|
+
this.activeGapLineElements = [];
|
|
2123
2157
|
}
|
|
2124
2158
|
_updateCachedIsUnsynced() {
|
|
2125
2159
|
this.cachedIsUnsynced =
|
|
@@ -2132,13 +2166,23 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2132
2166
|
return;
|
|
2133
2167
|
this.cachedLineData = this.lyrics.map(line => {
|
|
2134
2168
|
const wordGroups = [];
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2169
|
+
let currentGroupBuffer = [];
|
|
2170
|
+
line.text.forEach((syllable, idx) => {
|
|
2171
|
+
currentGroupBuffer.push(syllable);
|
|
2172
|
+
const nextSyllable = line.text[idx + 1];
|
|
2173
|
+
const endsWithDelimiter = !nextSyllable ||
|
|
2174
|
+
syllable.part === false ||
|
|
2175
|
+
/\s$/.test(syllable.text) ||
|
|
2176
|
+
(nextSyllable &&
|
|
2177
|
+
syllable.isBackground !==
|
|
2178
|
+
nextSyllable.isBackground);
|
|
2179
|
+
if (endsWithDelimiter) {
|
|
2180
|
+
wordGroups.push(currentGroupBuffer);
|
|
2181
|
+
currentGroupBuffer = [];
|
|
2141
2182
|
}
|
|
2183
|
+
});
|
|
2184
|
+
if (currentGroupBuffer.length > 0) {
|
|
2185
|
+
wordGroups.push(currentGroupBuffer);
|
|
2142
2186
|
}
|
|
2143
2187
|
const groupGrowable = new Array(wordGroups.length).fill(false);
|
|
2144
2188
|
const groupGlowing = new Array(wordGroups.length).fill(false);
|
|
@@ -2147,6 +2191,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2147
2191
|
const vwCharOffset = new Array(wordGroups.length).fill(0);
|
|
2148
2192
|
const vwStartMs = new Array(wordGroups.length).fill(0);
|
|
2149
2193
|
const vwEndMs = new Array(wordGroups.length).fill(0);
|
|
2194
|
+
let lineIsRTL = false;
|
|
2150
2195
|
let vwStart = 0;
|
|
2151
2196
|
while (vwStart < wordGroups.length) {
|
|
2152
2197
|
let vwEnd = vwStart;
|
|
@@ -2168,9 +2213,11 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2168
2213
|
const combinedDuration = combinedEnd - combinedStart;
|
|
2169
2214
|
const isCJK = /[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(combinedText);
|
|
2170
2215
|
const isRTL = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\u0590-\u05FF]/.test(combinedText);
|
|
2216
|
+
if (isRTL)
|
|
2217
|
+
lineIsRTL = true;
|
|
2171
2218
|
const hasHyphen = combinedText.includes('-');
|
|
2172
2219
|
const wordLen = combinedText.length;
|
|
2173
|
-
let isGrowableVW = !isCJK && !isRTL && !hasHyphen && wordLen > 0 && wordLen <=
|
|
2220
|
+
let isGrowableVW = !isCJK && !isRTL && !hasHyphen && wordLen > 0 && wordLen <= 7;
|
|
2174
2221
|
if (isGrowableVW) {
|
|
2175
2222
|
if (wordLen < 3) {
|
|
2176
2223
|
isGrowableVW =
|
|
@@ -2181,7 +2228,8 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2181
2228
|
combinedDuration >= 850 && combinedDuration >= wordLen * 190;
|
|
2182
2229
|
}
|
|
2183
2230
|
}
|
|
2184
|
-
const
|
|
2231
|
+
const isLineSynced = line.isWordSynced === false || line.text.some(s => s.lineSynced);
|
|
2232
|
+
const isGlowingVW = isGrowableVW && !isLineSynced;
|
|
2185
2233
|
let charOff = 0;
|
|
2186
2234
|
for (let gi = vwStart; gi <= vwEnd; gi += 1) {
|
|
2187
2235
|
groupGrowable[gi] = isGrowableVW;
|
|
@@ -2205,6 +2253,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2205
2253
|
vwCharOffset,
|
|
2206
2254
|
vwStartMs,
|
|
2207
2255
|
vwEndMs,
|
|
2256
|
+
lineIsRTL,
|
|
2208
2257
|
};
|
|
2209
2258
|
});
|
|
2210
2259
|
}
|
|
@@ -2285,15 +2334,17 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2285
2334
|
clearPreActiveClasses(exceptLineIndex = null) {
|
|
2286
2335
|
if (!this.lyricsContainer)
|
|
2287
2336
|
return;
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
.forEach(element => {
|
|
2291
|
-
const lineElement = element;
|
|
2337
|
+
const keptLines = [];
|
|
2338
|
+
for (const lineElement of this.preActiveLineElements) {
|
|
2292
2339
|
const lineIndex = AmLyrics.getLineIndexFromElement(lineElement);
|
|
2293
|
-
if (lineIndex
|
|
2340
|
+
if (lineIndex === exceptLineIndex) {
|
|
2341
|
+
keptLines.push(lineElement);
|
|
2342
|
+
}
|
|
2343
|
+
else {
|
|
2294
2344
|
lineElement.classList.remove('pre-active');
|
|
2295
2345
|
}
|
|
2296
|
-
}
|
|
2346
|
+
}
|
|
2347
|
+
this.preActiveLineElements = keptLines;
|
|
2297
2348
|
}
|
|
2298
2349
|
getPrimaryActiveLineIndex(activeIndices) {
|
|
2299
2350
|
if (activeIndices.length === 0)
|
|
@@ -2743,6 +2794,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2743
2794
|
// Clean up any lingering scroll animations before smooth scroll
|
|
2744
2795
|
for (const line of animatingLines) {
|
|
2745
2796
|
line.classList.remove('scroll-animate');
|
|
2797
|
+
line.style.removeProperty('will-change');
|
|
2746
2798
|
line.style.removeProperty('--scroll-delta');
|
|
2747
2799
|
line.style.removeProperty('--lyrics-line-delay');
|
|
2748
2800
|
line.style.removeProperty('--scroll-duration');
|
|
@@ -2801,6 +2853,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2801
2853
|
// --- Step 4: Re-add scroll-animate class to start fresh animations ---
|
|
2802
2854
|
for (const line of newAnimatingLines) {
|
|
2803
2855
|
line.classList.add('scroll-animate');
|
|
2856
|
+
line.style.willChange = 'transform';
|
|
2804
2857
|
animatingLines.push(line);
|
|
2805
2858
|
}
|
|
2806
2859
|
animState.isAnimating = true;
|
|
@@ -2817,6 +2870,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2817
2870
|
for (let i = 0; i < animatingLines.length; i += 1) {
|
|
2818
2871
|
const line = animatingLines[i];
|
|
2819
2872
|
line.classList.remove('scroll-animate');
|
|
2873
|
+
line.style.removeProperty('will-change');
|
|
2820
2874
|
line.style.removeProperty('--scroll-delta');
|
|
2821
2875
|
line.style.removeProperty('--lyrics-line-delay');
|
|
2822
2876
|
line.style.removeProperty('--scroll-duration');
|
|
@@ -2845,12 +2899,14 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2845
2899
|
'next-3',
|
|
2846
2900
|
'next-4',
|
|
2847
2901
|
];
|
|
2848
|
-
// Remove old position classes
|
|
2849
|
-
this.
|
|
2850
|
-
.
|
|
2851
|
-
|
|
2902
|
+
// Remove old position classes from tracked elements
|
|
2903
|
+
for (const el of this.positionedLineElements) {
|
|
2904
|
+
el.classList.remove(...positionClasses);
|
|
2905
|
+
}
|
|
2906
|
+
this.positionedLineElements = [];
|
|
2852
2907
|
// Add new position classes
|
|
2853
2908
|
lineToScroll.classList.add('lyrics-activest');
|
|
2909
|
+
this.positionedLineElements.push(lineToScroll);
|
|
2854
2910
|
const lineElements = Array.from(this.lyricsContainer.querySelectorAll('.lyrics-line'));
|
|
2855
2911
|
const scrollLineIndex = lineElements.indexOf(lineToScroll);
|
|
2856
2912
|
for (let i = Math.max(0, scrollLineIndex - 4); i <= Math.min(lineElements.length - 1, scrollLineIndex + 4); i += 1) {
|
|
@@ -2865,6 +2921,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2865
2921
|
element.classList.add(`prev-${Math.abs(position)}`);
|
|
2866
2922
|
else
|
|
2867
2923
|
element.classList.add(`next-${position}`);
|
|
2924
|
+
this.positionedLineElements.push(element);
|
|
2868
2925
|
}
|
|
2869
2926
|
}
|
|
2870
2927
|
}
|
|
@@ -2884,11 +2941,12 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2884
2941
|
paddingTop) < 1) {
|
|
2885
2942
|
return;
|
|
2886
2943
|
}
|
|
2887
|
-
// Skip scroll if near the bottom of content
|
|
2888
|
-
if (!forceScroll) {
|
|
2944
|
+
// Skip scroll if near the bottom of content and we aren't trying to scroll back up
|
|
2945
|
+
if (!forceScroll && !activeLine.classList.contains('lyrics-footer')) {
|
|
2889
2946
|
const parent = this.lyricsContainer;
|
|
2890
2947
|
const atBottom = parent.scrollTop + parent.clientHeight >= parent.scrollHeight - 50;
|
|
2891
|
-
|
|
2948
|
+
const targetTop = Math.max(0, -(paddingTop - activeLine.offsetTop));
|
|
2949
|
+
if (atBottom && targetTop > parent.scrollTop - 50) {
|
|
2892
2950
|
return;
|
|
2893
2951
|
}
|
|
2894
2952
|
}
|
|
@@ -2909,7 +2967,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2909
2967
|
* Update syllable highlight animation - apply CSS wipe animation
|
|
2910
2968
|
* (Exact copy from YouLyPlus _updateSyllableAnimation)
|
|
2911
2969
|
*/
|
|
2912
|
-
static updateSyllableAnimation(syllable) {
|
|
2970
|
+
static updateSyllableAnimation(syllable, elapsedTimeMs = 0) {
|
|
2913
2971
|
if (syllable.classList.contains('highlight'))
|
|
2914
2972
|
return;
|
|
2915
2973
|
const { classList } = syllable;
|
|
@@ -2937,8 +2995,8 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2937
2995
|
const baseDelayPerChar = finalDuration * 0.09;
|
|
2938
2996
|
const growDurationMs = finalDuration * 1.5;
|
|
2939
2997
|
allWordCharSpans.forEach(span => {
|
|
2940
|
-
const
|
|
2941
|
-
const
|
|
2998
|
+
const matrixScale = span.dataset.matrixScale || '1.1';
|
|
2999
|
+
const charOffsetX = span.dataset.charOffsetX || '0';
|
|
2942
3000
|
const shadowIntensity = span.dataset.shadowIntensity || '0.6';
|
|
2943
3001
|
const translateYPeak = span.dataset.translateYPeak || '-2';
|
|
2944
3002
|
const syllableCharIndex = parseFloat(span.dataset.syllableCharIndex || '0');
|
|
@@ -2946,13 +3004,13 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2946
3004
|
charAnimationsMap.set(span, `grow-dynamic ${growDurationMs}ms ease-in-out ${growDelay}ms forwards`);
|
|
2947
3005
|
styleUpdates.push({
|
|
2948
3006
|
element: span,
|
|
2949
|
-
property: '--
|
|
2950
|
-
value:
|
|
3007
|
+
property: '--matrix-scale',
|
|
3008
|
+
value: matrixScale,
|
|
2951
3009
|
});
|
|
2952
3010
|
styleUpdates.push({
|
|
2953
3011
|
element: span,
|
|
2954
|
-
property: '--
|
|
2955
|
-
value:
|
|
3012
|
+
property: '--char-offset-x',
|
|
3013
|
+
value: `${charOffsetX}px`,
|
|
2956
3014
|
});
|
|
2957
3015
|
styleUpdates.push({
|
|
2958
3016
|
element: span,
|
|
@@ -2962,7 +3020,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2962
3020
|
styleUpdates.push({
|
|
2963
3021
|
element: span,
|
|
2964
3022
|
property: '--translate-y-peak',
|
|
2965
|
-
value: `${translateYPeak}`,
|
|
3023
|
+
value: `${translateYPeak}px`,
|
|
2966
3024
|
});
|
|
2967
3025
|
});
|
|
2968
3026
|
}
|
|
@@ -2971,7 +3029,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2971
3029
|
charSpans.forEach((span, charIndex) => {
|
|
2972
3030
|
const startPct = parseFloat(span.dataset.wipeStart || '0');
|
|
2973
3031
|
const durationPct = parseFloat(span.dataset.wipeDuration || '0');
|
|
2974
|
-
const wipeDelay = syllableDurationMs * startPct;
|
|
3032
|
+
const wipeDelay = syllableDurationMs * startPct - elapsedTimeMs;
|
|
2975
3033
|
const wipeDuration = syllableDurationMs * durationPct;
|
|
2976
3034
|
const useStartAnimation = isFirstInContainer && charIndex === 0;
|
|
2977
3035
|
let charWipeAnimation = 'wipe';
|
|
@@ -2987,9 +3045,9 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
2987
3045
|
animationParts.push(existingAnimation.split(',')[0].trim());
|
|
2988
3046
|
}
|
|
2989
3047
|
if (charIndex > 0) {
|
|
2990
|
-
const arrivalTime = span.dataset.preWipeArrival
|
|
3048
|
+
const arrivalTime = (span.dataset.preWipeArrival
|
|
2991
3049
|
? parseFloat(span.dataset.preWipeArrival)
|
|
2992
|
-
:
|
|
3050
|
+
: syllableDurationMs * startPct) - elapsedTimeMs;
|
|
2993
3051
|
const constantDuration = parseFloat(span.dataset.preWipeDuration || '100');
|
|
2994
3052
|
const animDelay = arrivalTime - constantDuration;
|
|
2995
3053
|
if (constantDuration > 0) {
|
|
@@ -3019,12 +3077,13 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3019
3077
|
return;
|
|
3020
3078
|
const currentWipeAnimation = isGap ? 'fade-gap' : wipeAnimation;
|
|
3021
3079
|
// eslint-disable-next-line no-param-reassign
|
|
3022
|
-
syllable.style.animation = `${currentWipeAnimation} ${visualDuration}ms ${isGap ? 'ease-out' : 'linear'} forwards`;
|
|
3080
|
+
syllable.style.animation = `${currentWipeAnimation} ${visualDuration}ms ${isGap ? 'ease-out' : 'linear'} ${-elapsedTimeMs}ms forwards`;
|
|
3023
3081
|
}
|
|
3024
3082
|
// --- WRITE PHASE ---
|
|
3025
3083
|
classList.remove('pre-highlight');
|
|
3026
3084
|
classList.add('highlight');
|
|
3027
3085
|
for (const [span, animationString] of charAnimationsMap.entries()) {
|
|
3086
|
+
span.style.willChange = 'transform';
|
|
3028
3087
|
span.style.animation = animationString;
|
|
3029
3088
|
}
|
|
3030
3089
|
// Apply style updates
|
|
@@ -3051,6 +3110,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3051
3110
|
syllable.querySelectorAll('span.char').forEach(span => {
|
|
3052
3111
|
const el = span;
|
|
3053
3112
|
el.style.animation = '';
|
|
3113
|
+
el.style.willChange = '';
|
|
3054
3114
|
el.style.transition = 'none';
|
|
3055
3115
|
el.style.backgroundColor = 'var(--lyplus-text-secondary)';
|
|
3056
3116
|
});
|
|
@@ -3064,6 +3124,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3064
3124
|
const el = span;
|
|
3065
3125
|
el.style.removeProperty('background-color');
|
|
3066
3126
|
el.style.removeProperty('transition');
|
|
3127
|
+
el.style.removeProperty('will-change');
|
|
3067
3128
|
});
|
|
3068
3129
|
});
|
|
3069
3130
|
}
|
|
@@ -3093,7 +3154,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3093
3154
|
const syllable = syllables[i];
|
|
3094
3155
|
const startTime = parseFloat(syllable.getAttribute('data-start-time') || '0');
|
|
3095
3156
|
const endTime = parseFloat(syllable.getAttribute('data-end-time') || '0');
|
|
3096
|
-
if (startTime) {
|
|
3157
|
+
if (Number.isFinite(startTime) && Number.isFinite(endTime)) {
|
|
3097
3158
|
const { classList } = syllable;
|
|
3098
3159
|
const hasHighlight = classList.contains('highlight');
|
|
3099
3160
|
const hasFinished = classList.contains('finished');
|
|
@@ -3117,7 +3178,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3117
3178
|
if (currentTimeMs >= startTime && currentTimeMs <= endTime) {
|
|
3118
3179
|
// Currently active
|
|
3119
3180
|
if (!hasHighlight) {
|
|
3120
|
-
AmLyrics.updateSyllableAnimation(syllable);
|
|
3181
|
+
AmLyrics.updateSyllableAnimation(syllable, currentTimeMs - startTime);
|
|
3121
3182
|
}
|
|
3122
3183
|
if (hasFinished) {
|
|
3123
3184
|
classList.remove('finished');
|
|
@@ -3127,7 +3188,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3127
3188
|
// Finished
|
|
3128
3189
|
if (!hasFinished) {
|
|
3129
3190
|
if (!hasHighlight) {
|
|
3130
|
-
AmLyrics.updateSyllableAnimation(syllable);
|
|
3191
|
+
AmLyrics.updateSyllableAnimation(syllable, currentTimeMs - startTime);
|
|
3131
3192
|
}
|
|
3132
3193
|
classList.add('finished');
|
|
3133
3194
|
}
|
|
@@ -3379,7 +3440,6 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3379
3440
|
}
|
|
3380
3441
|
// Set both old internal CSS variables (for backward compatibility)
|
|
3381
3442
|
// and new public CSS variables (which take precedence)
|
|
3382
|
-
this.style.setProperty('--hover-background-color', this.hoverBackgroundColor);
|
|
3383
3443
|
this.style.setProperty('--highlight-color', this.highlightColor);
|
|
3384
3444
|
const sourceLabel = this.lyricsSource ?? 'Unavailable';
|
|
3385
3445
|
const isUnsynced = this.cachedIsUnsynced;
|
|
@@ -3421,7 +3481,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3421
3481
|
syllable.romanizedText &&
|
|
3422
3482
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
3423
3483
|
? b `<span
|
|
3424
|
-
class="lyrics-syllable transliteration ${syllable.lineSynced
|
|
3484
|
+
class="lyrics-syllable transliteration no-chars ${syllable.lineSynced
|
|
3425
3485
|
? 'line-synced'
|
|
3426
3486
|
: ''}"
|
|
3427
3487
|
data-start-time="${startTimeMs}"
|
|
@@ -3432,21 +3492,24 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3432
3492
|
>${syllable.romanizedText}</span
|
|
3433
3493
|
>`
|
|
3434
3494
|
: '';
|
|
3435
|
-
return b `<span class="lyrics-word"
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3495
|
+
return b `<span class="lyrics-word"
|
|
3496
|
+
><span
|
|
3497
|
+
class="lyrics-syllable-wrap${bgRomanizedText
|
|
3498
|
+
? ' has-transliteration'
|
|
3499
|
+
: ''}"
|
|
3500
|
+
><span
|
|
3501
|
+
class="lyrics-syllable no-chars${syllable.lineSynced
|
|
3502
|
+
? ' line-synced'
|
|
3440
3503
|
: ''}"
|
|
3441
3504
|
data-start-time="${startTimeMs}"
|
|
3442
3505
|
data-end-time="${endTimeMs}"
|
|
3443
3506
|
data-duration="${durationMs}"
|
|
3444
3507
|
data-syllable-index="${syllableIndex}"
|
|
3508
|
+
data-wipe-ratio="1"
|
|
3445
3509
|
>${syllable.text}</span
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
</span>`;
|
|
3510
|
+
>${bgRomanizedText}</span
|
|
3511
|
+
></span
|
|
3512
|
+
>`;
|
|
3450
3513
|
})}
|
|
3451
3514
|
</p>`
|
|
3452
3515
|
: '';
|
|
@@ -3464,8 +3527,11 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3464
3527
|
const vwFullText = lineData?.vwFullText ?? [];
|
|
3465
3528
|
const vwFullDuration = lineData?.vwFullDuration ?? [];
|
|
3466
3529
|
const vwCharOffset = lineData?.vwCharOffset ?? [];
|
|
3530
|
+
const lineIsRTL = lineData?.lineIsRTL ?? false;
|
|
3467
3531
|
// Create main vocals using YouLyPlus syllable structure
|
|
3468
|
-
const mainVocalElement = b `<p
|
|
3532
|
+
const mainVocalElement = b `<p
|
|
3533
|
+
class="main-vocal-container ${lineIsRTL ? 'rtl-text' : ''}"
|
|
3534
|
+
>
|
|
3469
3535
|
${wordGroups.map((group, groupIdx) => {
|
|
3470
3536
|
const isGrowable = groupGrowable[groupIdx];
|
|
3471
3537
|
const isGlowing = groupGlowing[groupIdx];
|
|
@@ -3475,12 +3541,21 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3475
3541
|
const wordNumChars = wordText.length;
|
|
3476
3542
|
const groupCharOffset = isGrowable ? vwCharOffset[groupIdx] : 0;
|
|
3477
3543
|
let sylCharAccumulator = 0;
|
|
3544
|
+
const groupText = group.map(s => s.text).join('');
|
|
3545
|
+
const shouldAllowBreak = groupText.trim().length >= 16 ||
|
|
3546
|
+
/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/.test(groupText);
|
|
3547
|
+
// Calculate dynamic rise duration based on the audio duration of the word
|
|
3548
|
+
const wordStartTimeMs = group[0].timestamp;
|
|
3549
|
+
const wordEndTimeMs = group[group.length - 1].endtime;
|
|
3550
|
+
const actualDurationMs = wordEndTimeMs - wordStartTimeMs;
|
|
3551
|
+
// Base float is 0.8s, plus a portion of the audio duration, capped between 1.0s and 2.5s
|
|
3552
|
+
const riseDuration = Math.max(1.2, Math.min(2.5, 1.2 + (actualDurationMs / 1000) * 0.6));
|
|
3478
3553
|
return b `<span
|
|
3479
|
-
class="lyrics-word
|
|
3480
|
-
? 'glowing'
|
|
3481
|
-
: ''}
|
|
3482
|
-
|
|
3483
|
-
|
|
3554
|
+
class="lyrics-word${isGrowable ? ' growable' : ''}${isGlowing
|
|
3555
|
+
? ' glowing'
|
|
3556
|
+
: ''}${shouldAllowBreak ? ' allow-break' : ''}"
|
|
3557
|
+
style="--rise-duration: ${riseDuration}s"
|
|
3558
|
+
>${group.map((syllable, sylIdx) => {
|
|
3484
3559
|
const startTimeMs = syllable.timestamp;
|
|
3485
3560
|
const endTimeMs = syllable.endtime;
|
|
3486
3561
|
const durationMs = endTimeMs - startTimeMs;
|
|
@@ -3489,7 +3564,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3489
3564
|
syllable.romanizedText &&
|
|
3490
3565
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
3491
3566
|
? b `<span
|
|
3492
|
-
class="lyrics-syllable transliteration ${groupLineSynced
|
|
3567
|
+
class="lyrics-syllable transliteration no-chars ${groupLineSynced
|
|
3493
3568
|
? 'line-synced'
|
|
3494
3569
|
: ''}"
|
|
3495
3570
|
data-start-time="${startTimeMs}"
|
|
@@ -3566,17 +3641,22 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3566
3641
|
data-wipe-duration="${(1 / numCharsInSyllable).toFixed(4)}"
|
|
3567
3642
|
data-horizontal-offset="${horizontalOffset.toFixed(2)}"
|
|
3568
3643
|
data-max-scale="${charMaxScale.toFixed(3)}"
|
|
3644
|
+
data-matrix-scale="${(charMaxScale * 0.98).toFixed(3)}"
|
|
3645
|
+
data-char-offset-x="${(horizontalOffset * 0.98).toFixed(2)}"
|
|
3569
3646
|
data-shadow-intensity="${charShadowIntensity.toFixed(3)}"
|
|
3570
3647
|
data-translate-y-peak="${charTranslateYPeak.toFixed(3)}"
|
|
3571
3648
|
>${char}</span
|
|
3572
3649
|
>`;
|
|
3573
3650
|
})}`;
|
|
3574
3651
|
}
|
|
3575
|
-
return b `<span
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
? 'line-synced'
|
|
3652
|
+
return b `<span
|
|
3653
|
+
class="lyrics-syllable-wrap${romanizedText
|
|
3654
|
+
? ' has-transliteration'
|
|
3579
3655
|
: ''}"
|
|
3656
|
+
><span
|
|
3657
|
+
class="lyrics-syllable${groupLineSynced
|
|
3658
|
+
? ' line-synced'
|
|
3659
|
+
: ''}${isGrowable ? ' has-chars' : ' no-chars'}"
|
|
3580
3660
|
data-start-time="${startTimeMs}"
|
|
3581
3661
|
data-end-time="${endTimeMs}"
|
|
3582
3662
|
data-duration="${durationMs}"
|
|
@@ -3584,11 +3664,10 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3584
3664
|
data-syllable-index="${sylIdx}"
|
|
3585
3665
|
data-wipe-ratio="1"
|
|
3586
3666
|
>${syllableContent}</span
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
</span>`;
|
|
3667
|
+
>${romanizedText}</span
|
|
3668
|
+
>`;
|
|
3669
|
+
})}</span
|
|
3670
|
+
>`;
|
|
3592
3671
|
})}
|
|
3593
3672
|
</p>`;
|
|
3594
3673
|
// Translation container (if enabled)
|
|
@@ -3610,7 +3689,11 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3610
3689
|
line.romanizedText &&
|
|
3611
3690
|
!line.text.some(s => s.romanizedText) &&
|
|
3612
3691
|
line.romanizedText.trim() !== fullLineText
|
|
3613
|
-
? b `<div
|
|
3692
|
+
? b `<div
|
|
3693
|
+
class="lyrics-romanization-container ${lineIsRTL
|
|
3694
|
+
? 'rtl-text'
|
|
3695
|
+
: ''}"
|
|
3696
|
+
>
|
|
3614
3697
|
${line.romanizedText}
|
|
3615
3698
|
</div>`
|
|
3616
3699
|
: '';
|
|
@@ -3630,42 +3713,37 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3630
3713
|
data-end-time="${gapForLine.gapEnd}"
|
|
3631
3714
|
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};"
|
|
3632
3715
|
>
|
|
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
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
></span>
|
|
3665
|
-
</span>
|
|
3666
|
-
</span>
|
|
3667
|
-
</p>
|
|
3668
|
-
</div>
|
|
3716
|
+
<p class="main-vocal-container">
|
|
3717
|
+
<span class="lyrics-word"
|
|
3718
|
+
><span class="lyrics-syllable-wrap"
|
|
3719
|
+
><span
|
|
3720
|
+
class="lyrics-syllable"
|
|
3721
|
+
data-start-time="${gapForLine.gapStart}"
|
|
3722
|
+
data-end-time="${gapForLine.gapStart + dotDuration}"
|
|
3723
|
+
data-duration="${dotDuration}"
|
|
3724
|
+
data-wipe-ratio="1"
|
|
3725
|
+
data-syllable-index="0"
|
|
3726
|
+
></span></span
|
|
3727
|
+
><span class="lyrics-syllable-wrap"
|
|
3728
|
+
><span
|
|
3729
|
+
class="lyrics-syllable"
|
|
3730
|
+
data-start-time="${gapForLine.gapStart + dotDuration}"
|
|
3731
|
+
data-end-time="${gapForLine.gapStart + dotDuration * 2}"
|
|
3732
|
+
data-duration="${dotDuration}"
|
|
3733
|
+
data-wipe-ratio="1"
|
|
3734
|
+
data-syllable-index="1"
|
|
3735
|
+
></span></span
|
|
3736
|
+
><span class="lyrics-syllable-wrap"
|
|
3737
|
+
><span
|
|
3738
|
+
class="lyrics-syllable"
|
|
3739
|
+
data-start-time="${gapForLine.gapStart + dotDuration * 2}"
|
|
3740
|
+
data-end-time="${gapForLine.gapEnd}"
|
|
3741
|
+
data-duration="${dotDuration}"
|
|
3742
|
+
data-wipe-ratio="1"
|
|
3743
|
+
data-syllable-index="2"
|
|
3744
|
+
></span></span
|
|
3745
|
+
></span>
|
|
3746
|
+
</p>
|
|
3669
3747
|
</div>`;
|
|
3670
3748
|
}
|
|
3671
3749
|
return b `
|
|
@@ -3674,7 +3752,7 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3674
3752
|
id="${lineId}"
|
|
3675
3753
|
class="lyrics-line ${line.alignment === 'end'
|
|
3676
3754
|
? 'singer-right'
|
|
3677
|
-
: 'singer-left'}"
|
|
3755
|
+
: 'singer-left'} ${lineIsRTL ? 'rtl-text' : ''}"
|
|
3678
3756
|
data-start-time="${lineStartTime}"
|
|
3679
3757
|
data-end-time="${lineEndTime}"
|
|
3680
3758
|
@click=${() => this.handleLineClick(line)}
|
|
@@ -3685,11 +3763,11 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3685
3763
|
}
|
|
3686
3764
|
}}
|
|
3687
3765
|
>
|
|
3688
|
-
<div class="lyrics-line-container">
|
|
3766
|
+
<div class="lyrics-line-container ${lineIsRTL ? 'rtl-text' : ''}">
|
|
3689
3767
|
${bgPlacement === 'before' ? backgroundVocalElement : ''}
|
|
3690
3768
|
${mainVocalElement}
|
|
3691
3769
|
${bgPlacement === 'after' ? backgroundVocalElement : ''}
|
|
3692
|
-
${
|
|
3770
|
+
${lineRomanizationElement} ${translationElement}
|
|
3693
3771
|
</div>
|
|
3694
3772
|
</div>
|
|
3695
3773
|
`;
|
|
@@ -3802,13 +3880,13 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3802
3880
|
${renderContent()}
|
|
3803
3881
|
${!this.isLoading
|
|
3804
3882
|
? b `
|
|
3805
|
-
<footer class="lyrics-footer">
|
|
3883
|
+
<footer class="lyrics-footer lyrics-line">
|
|
3806
3884
|
<div class="footer-content">
|
|
3807
3885
|
<span
|
|
3808
3886
|
class="source-info"
|
|
3809
3887
|
style="display: flex; align-items: center; gap: 8px;"
|
|
3810
3888
|
>
|
|
3811
|
-
|
|
3889
|
+
<b style="font-weight: 750;">Source</b> ${sourceLabel}
|
|
3812
3890
|
${(this.availableSources &&
|
|
3813
3891
|
this.availableSources.length > 1) ||
|
|
3814
3892
|
!this.hasFetchedAllProviders
|
|
@@ -3851,15 +3929,25 @@ let AmLyrics$1 = class AmLyrics extends i {
|
|
|
3851
3929
|
`
|
|
3852
3930
|
: ''}
|
|
3853
3931
|
</span>
|
|
3854
|
-
|
|
3855
|
-
|
|
3932
|
+
${this.songwriters
|
|
3933
|
+
? b `<span
|
|
3934
|
+
class="songwriters-info"
|
|
3935
|
+
style="margin-top: 4px; font-weight: normal; font-size: 0.9em;"
|
|
3936
|
+
>
|
|
3937
|
+
<b style="font-weight: 750;">Songwriters</b> ${this
|
|
3938
|
+
.songwriters}
|
|
3939
|
+
</span>`
|
|
3940
|
+
: ''}
|
|
3941
|
+
<span class="version-info" style="margin-top: 8px;">
|
|
3942
|
+
<b style="font-weight: 750;">am-lyrics</b> v${VERSION} •
|
|
3856
3943
|
|
|
3857
3944
|
<a
|
|
3858
3945
|
href="https://github.com/uimaxbai/apple-music-web-components"
|
|
3859
3946
|
target="_blank"
|
|
3860
3947
|
rel="noopener noreferrer"
|
|
3861
|
-
|
|
3862
|
-
|
|
3948
|
+
style="display: inline-flex; align-items: center; gap: 4px;"
|
|
3949
|
+
>Star me on GitHub
|
|
3950
|
+
</a>
|
|
3863
3951
|
</span>
|
|
3864
3952
|
</div>
|
|
3865
3953
|
</footer>
|
|
@@ -3896,6 +3984,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
3896
3984
|
--lyplus-font-size-base: 32px;
|
|
3897
3985
|
--lyplus-font-size-base-grow: 24.5;
|
|
3898
3986
|
--lyplus-font-size-subtext: 0.6em;
|
|
3987
|
+
--char-rise-y: calc(-0.035 * var(--lyplus-font-size-base));
|
|
3899
3988
|
|
|
3900
3989
|
--lyplus-blur-amount: 0.07em;
|
|
3901
3990
|
--lyplus-blur-amount-near: 0.035em;
|
|
@@ -3929,7 +4018,6 @@ AmLyrics$1.styles = i$3 `
|
|
|
3929
4018
|
-webkit-overflow-scrolling: touch;
|
|
3930
4019
|
box-sizing: border-box;
|
|
3931
4020
|
scrollbar-width: none;
|
|
3932
|
-
transform: translateZ(0);
|
|
3933
4021
|
}
|
|
3934
4022
|
|
|
3935
4023
|
.lyrics-container::-webkit-scrollbar {
|
|
@@ -3940,11 +4028,13 @@ AmLyrics$1.styles = i$3 `
|
|
|
3940
4028
|
.lyrics-container.touch-scrolling .lyrics-line,
|
|
3941
4029
|
.lyrics-container.touch-scrolling .lyrics-plus-metadata {
|
|
3942
4030
|
transition: none !important;
|
|
4031
|
+
filter: none !important;
|
|
3943
4032
|
}
|
|
3944
4033
|
|
|
3945
4034
|
/* Apply smooth gliding transition for mouse-wheel scrolling */
|
|
3946
4035
|
.lyrics-container.wheel-scrolling .lyrics-line {
|
|
3947
4036
|
transition: transform 0.3s ease-out !important;
|
|
4037
|
+
filter: none !important;
|
|
3948
4038
|
}
|
|
3949
4039
|
|
|
3950
4040
|
.lyrics-line.scroll-animate {
|
|
@@ -3971,18 +4061,13 @@ AmLyrics$1.styles = i$3 `
|
|
|
3971
4061
|
font-size: var(--lyplus-font-size-base);
|
|
3972
4062
|
cursor: pointer;
|
|
3973
4063
|
transform-origin: left;
|
|
3974
|
-
transform: translateZ(1px);
|
|
3975
4064
|
transition:
|
|
3976
4065
|
opacity 0.3s ease,
|
|
3977
4066
|
transform 0.4s cubic-bezier(0.41, 0, 0.12, 0.99)
|
|
3978
4067
|
var(--lyrics-line-delay, 0ms),
|
|
3979
4068
|
filter 0.3s ease;
|
|
3980
|
-
will-change: transform, filter, opacity;
|
|
3981
4069
|
content-visibility: auto;
|
|
3982
4070
|
text-rendering: optimizeLegibility;
|
|
3983
|
-
overflow-wrap: break-word;
|
|
3984
|
-
mix-blend-mode: lighten;
|
|
3985
|
-
border-radius: var(--lyplus-border-radius-base);
|
|
3986
4071
|
}
|
|
3987
4072
|
|
|
3988
4073
|
.lyrics-line:not(.scroll-animate) {
|
|
@@ -4002,8 +4087,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4002
4087
|
|
|
4003
4088
|
.lyrics-line.active .lyrics-line-container,
|
|
4004
4089
|
.lyrics-line.pre-active .lyrics-line-container {
|
|
4005
|
-
transform: scale3d(1.001, 1.001, 1);
|
|
4006
|
-
will-change: transform;
|
|
4090
|
+
transform: scale3d(1.001, 1.001, 1) translateZ(0);
|
|
4007
4091
|
transition:
|
|
4008
4092
|
transform 0.5s ease,
|
|
4009
4093
|
background-color 0.18s,
|
|
@@ -4048,12 +4132,10 @@ AmLyrics$1.styles = i$3 `
|
|
|
4048
4132
|
.lyrics-line.active {
|
|
4049
4133
|
opacity: 1;
|
|
4050
4134
|
color: var(--lyplus-text-primary);
|
|
4051
|
-
will-change: transform, opacity;
|
|
4052
4135
|
}
|
|
4053
4136
|
|
|
4054
4137
|
.lyrics-line.pre-active {
|
|
4055
4138
|
opacity: 1;
|
|
4056
|
-
will-change: transform, opacity;
|
|
4057
4139
|
}
|
|
4058
4140
|
|
|
4059
4141
|
.lyrics-line.singer-right {
|
|
@@ -4067,6 +4149,18 @@ AmLyrics$1.styles = i$3 `
|
|
|
4067
4149
|
|
|
4068
4150
|
.lyrics-line.rtl-text {
|
|
4069
4151
|
direction: rtl;
|
|
4152
|
+
text-align: right !important;
|
|
4153
|
+
transform-origin: right;
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4156
|
+
.lyrics-line.rtl-text .lyrics-line-container,
|
|
4157
|
+
.lyrics-line.rtl-text .main-vocal-container {
|
|
4158
|
+
transform-origin: right;
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
.lyrics-line.rtl-text .lyrics-romanization-container,
|
|
4162
|
+
.lyrics-line.rtl-text .lyrics-translation-container {
|
|
4163
|
+
text-align: right;
|
|
4070
4164
|
}
|
|
4071
4165
|
|
|
4072
4166
|
/* --- Unsynced (Plain Text) Lyrics Overrides --- */
|
|
@@ -4098,7 +4192,8 @@ AmLyrics$1.styles = i$3 `
|
|
|
4098
4192
|
|
|
4099
4193
|
@media (hover: hover) and (pointer: fine) {
|
|
4100
4194
|
.lyrics-line:hover {
|
|
4101
|
-
|
|
4195
|
+
filter: none !important;
|
|
4196
|
+
opacity: 1 !important;
|
|
4102
4197
|
}
|
|
4103
4198
|
.lyrics-container.is-unsynced .lyrics-line:hover {
|
|
4104
4199
|
background: transparent !important;
|
|
@@ -4128,6 +4223,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4128
4223
|
|
|
4129
4224
|
/* Unblur all lines when user is scrolling */
|
|
4130
4225
|
.lyrics-container.user-scrolling .lyrics-line {
|
|
4226
|
+
transition: none !important;
|
|
4131
4227
|
filter: none !important;
|
|
4132
4228
|
opacity: 0.8 !important;
|
|
4133
4229
|
}
|
|
@@ -4144,6 +4240,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4144
4240
|
.lyrics-word:not(.allow-break) {
|
|
4145
4241
|
display: inline-block;
|
|
4146
4242
|
vertical-align: baseline;
|
|
4243
|
+
white-space: nowrap;
|
|
4147
4244
|
}
|
|
4148
4245
|
|
|
4149
4246
|
.lyrics-word.allow-break {
|
|
@@ -4154,7 +4251,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4154
4251
|
display: inline;
|
|
4155
4252
|
}
|
|
4156
4253
|
|
|
4157
|
-
.lyrics-syllable-wrap
|
|
4254
|
+
.lyrics-syllable-wrap.has-transliteration {
|
|
4158
4255
|
display: inline-flex;
|
|
4159
4256
|
flex-direction: column;
|
|
4160
4257
|
align-items: start;
|
|
@@ -4182,7 +4279,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4182
4279
|
transition: transform 1s ease !important;
|
|
4183
4280
|
}
|
|
4184
4281
|
|
|
4185
|
-
.lyrics-syllable.finished
|
|
4282
|
+
.lyrics-syllable.finished.has-chars {
|
|
4186
4283
|
background-color: transparent;
|
|
4187
4284
|
}
|
|
4188
4285
|
|
|
@@ -4191,19 +4288,16 @@ AmLyrics$1.styles = i$3 `
|
|
|
4191
4288
|
}
|
|
4192
4289
|
|
|
4193
4290
|
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable {
|
|
4194
|
-
transform: translateY(0.001%) translateZ(1px);
|
|
4195
4291
|
transition:
|
|
4196
4292
|
transform 1s ease,
|
|
4197
4293
|
background-color 0.5s,
|
|
4198
4294
|
color 0.5s;
|
|
4199
|
-
will-change: transform, background;
|
|
4200
4295
|
}
|
|
4201
4296
|
|
|
4202
4297
|
/* --- Wipe Highlight Effect --- */
|
|
4298
|
+
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable.highlight.no-chars,
|
|
4203
4299
|
.lyrics-line.active:not(.lyrics-gap)
|
|
4204
|
-
.lyrics-syllable.highlight
|
|
4205
|
-
.lyrics-line.active:not(.lyrics-gap)
|
|
4206
|
-
.lyrics-syllable.pre-highlight:not(:has(.char)) {
|
|
4300
|
+
.lyrics-syllable.pre-highlight.no-chars {
|
|
4207
4301
|
background-repeat: no-repeat;
|
|
4208
4302
|
background-image:
|
|
4209
4303
|
linear-gradient(
|
|
@@ -4245,11 +4339,19 @@ AmLyrics$1.styles = i$3 `
|
|
|
4245
4339
|
right;
|
|
4246
4340
|
}
|
|
4247
4341
|
|
|
4342
|
+
/* Non-growable words float up with a gentle curve */
|
|
4248
4343
|
.lyrics-line.active:not(.lyrics-gap)
|
|
4249
4344
|
.lyrics-word:not(.growable)
|
|
4250
|
-
.lyrics-syllable.highlight
|
|
4345
|
+
.lyrics-syllable.highlight {
|
|
4346
|
+
transform: translateY(-3.5%);
|
|
4347
|
+
transition:
|
|
4348
|
+
transform var(--rise-duration, 1.5s) cubic-bezier(0.22, 1, 0.36, 1),
|
|
4349
|
+
background-color 0.5s,
|
|
4350
|
+
color 0.5s;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4251
4353
|
.lyrics-word.growable .lyrics-syllable.cleanup .char {
|
|
4252
|
-
transform: translateY(-3.5%)
|
|
4354
|
+
transform: translateY(-3.5%);
|
|
4253
4355
|
}
|
|
4254
4356
|
|
|
4255
4357
|
.lyrics-line.active:not(.lyrics-gap) .lyrics-syllable.highlight.finished {
|
|
@@ -4276,7 +4378,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4276
4378
|
}
|
|
4277
4379
|
|
|
4278
4380
|
/* Syllable with chars: make syllable transparent, chars handle color */
|
|
4279
|
-
.lyrics-line .lyrics-syllable
|
|
4381
|
+
.lyrics-line .lyrics-syllable.has-chars:not(.finished) {
|
|
4280
4382
|
background-color: transparent;
|
|
4281
4383
|
color: transparent;
|
|
4282
4384
|
}
|
|
@@ -4289,6 +4391,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4289
4391
|
font-feature-settings: 'liga' 0;
|
|
4290
4392
|
background-clip: text;
|
|
4291
4393
|
-webkit-background-clip: text;
|
|
4394
|
+
backface-visibility: hidden;
|
|
4292
4395
|
transition:
|
|
4293
4396
|
color 0.7s,
|
|
4294
4397
|
background-color 0.7s,
|
|
@@ -4324,11 +4427,9 @@ AmLyrics$1.styles = i$3 `
|
|
|
4324
4427
|
-0.5em 0%,
|
|
4325
4428
|
-0.25em 0%;
|
|
4326
4429
|
transform-origin: 50% 80%;
|
|
4327
|
-
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
|
4328
4430
|
transition:
|
|
4329
4431
|
transform 0.7s ease,
|
|
4330
4432
|
color 0.18s;
|
|
4331
|
-
will-change: background, transform;
|
|
4332
4433
|
}
|
|
4333
4434
|
|
|
4334
4435
|
.lyrics-line.active .lyrics-syllable span.char.highlight {
|
|
@@ -4380,6 +4481,8 @@ AmLyrics$1.styles = i$3 `
|
|
|
4380
4481
|
box-sizing: content-box;
|
|
4381
4482
|
background-clip: unset;
|
|
4382
4483
|
transform-origin: top;
|
|
4484
|
+
content-visibility: visible !important;
|
|
4485
|
+
contain: none !important;
|
|
4383
4486
|
transition:
|
|
4384
4487
|
opacity 160ms ease-out,
|
|
4385
4488
|
transform var(--scroll-duration, 280ms) var(--lyrics-line-delay, 0ms);
|
|
@@ -4390,41 +4493,35 @@ AmLyrics$1.styles = i$3 `
|
|
|
4390
4493
|
transition:
|
|
4391
4494
|
opacity 160ms ease-out,
|
|
4392
4495
|
transform var(--scroll-duration, 280ms);
|
|
4393
|
-
will-change: opacity;
|
|
4394
4496
|
}
|
|
4395
4497
|
|
|
4396
4498
|
/* Exiting state: quickly collapse width and height so dots don't distort page, or remove max-height transition */
|
|
4397
4499
|
.lyrics-gap.gap-exiting {
|
|
4398
4500
|
opacity: 1;
|
|
4399
|
-
transition: transform var(--scroll-duration, 280ms);
|
|
4400
4501
|
}
|
|
4401
4502
|
|
|
4402
4503
|
.lyrics-gap .main-vocal-container {
|
|
4403
|
-
transform: translateY(-25%) scale(1)
|
|
4504
|
+
transform: translateY(-25%) scale(1);
|
|
4404
4505
|
transition: transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
4405
4506
|
}
|
|
4406
4507
|
|
|
4407
|
-
/* Jump animation plays during exit */
|
|
4408
|
-
.lyrics-gap.gap-exiting .main-vocal-container {
|
|
4409
|
-
animation: gap-ended var(--gap-exit-duration, 360ms)
|
|
4410
|
-
cubic-bezier(0.33, 1, 0.68, 1) forwards;
|
|
4411
|
-
}
|
|
4412
|
-
|
|
4413
4508
|
.lyrics-gap:not(.active):not(.gap-exiting) .main-vocal-container {
|
|
4414
|
-
transform: translateY(-25%) scale(0)
|
|
4415
|
-
}
|
|
4416
|
-
|
|
4417
|
-
.lyrics-gap:not(.active):not(.gap-exiting)
|
|
4418
|
-
.main-vocal-container
|
|
4419
|
-
.lyrics-word {
|
|
4420
|
-
animation-play-state: paused;
|
|
4509
|
+
transform: translateY(-25%) scale(0);
|
|
4421
4510
|
}
|
|
4422
4511
|
|
|
4423
|
-
|
|
4512
|
+
/* Pulse — must come BEFORE .gap-exiting so exiting wins via specificity+order */
|
|
4513
|
+
.lyrics-gap.active .main-vocal-container {
|
|
4424
4514
|
animation: gap-loop var(--gap-pulse-duration, 4000ms) ease-in-out infinite
|
|
4425
4515
|
alternate;
|
|
4426
4516
|
animation-delay: var(--gap-loop-delay, 0ms);
|
|
4427
|
-
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
/* Jump animation plays during exit — disable transition so animation wins.
|
|
4520
|
+
Placed AFTER .active so it wins when both classes are present briefly. */
|
|
4521
|
+
.lyrics-gap.gap-exiting .main-vocal-container {
|
|
4522
|
+
animation: gap-ended var(--gap-exit-duration, 360ms)
|
|
4523
|
+
cubic-bezier(0.33, 1, 0.68, 1) forwards;
|
|
4524
|
+
transition: none !important;
|
|
4428
4525
|
}
|
|
4429
4526
|
|
|
4430
4527
|
.lyrics-gap .lyrics-syllable {
|
|
@@ -4475,20 +4572,17 @@ AmLyrics$1.styles = i$3 `
|
|
|
4475
4572
|
background-clip: unset;
|
|
4476
4573
|
}
|
|
4477
4574
|
|
|
4478
|
-
.lyrics-gap.active .lyrics-syllable.highlight,
|
|
4479
4575
|
.lyrics-gap.active .lyrics-syllable.finished,
|
|
4480
|
-
.lyrics-gap.gap-exiting .lyrics-syllable,
|
|
4481
|
-
.lyrics-gap:not(.active).post-active-line
|
|
4482
|
-
|
|
4576
|
+
.lyrics-gap.gap-exiting .lyrics-syllable.finished,
|
|
4577
|
+
.lyrics-gap:not(.active):not(.gap-exiting).post-active-line
|
|
4578
|
+
.lyrics-syllable,
|
|
4579
|
+
.lyrics-gap:not(.active):not(.gap-exiting).lyrics-activest
|
|
4580
|
+
.lyrics-syllable {
|
|
4483
4581
|
background-color: var(--lyplus-text-primary);
|
|
4484
4582
|
animation: none !important;
|
|
4485
4583
|
opacity: 1;
|
|
4486
4584
|
}
|
|
4487
4585
|
|
|
4488
|
-
.lyrics-gap.active .lyrics-syllable.finished {
|
|
4489
|
-
animation: none !important;
|
|
4490
|
-
}
|
|
4491
|
-
|
|
4492
4586
|
/* ==========================================================================
|
|
4493
4587
|
METADATA & FOOTER STYLES
|
|
4494
4588
|
========================================================================== */
|
|
@@ -4517,12 +4611,49 @@ AmLyrics$1.styles = i$3 `
|
|
|
4517
4611
|
align-items: center;
|
|
4518
4612
|
flex-wrap: wrap;
|
|
4519
4613
|
text-align: left;
|
|
4520
|
-
font-size:
|
|
4521
|
-
color: rgba(255, 255, 255, 0.
|
|
4522
|
-
padding:
|
|
4523
|
-
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
4614
|
+
font-size: 1.2em;
|
|
4615
|
+
color: rgba(255, 255, 255, 0.6);
|
|
4616
|
+
padding: 20px 0 50vh 0;
|
|
4524
4617
|
margin-top: 10px;
|
|
4525
|
-
font-weight:
|
|
4618
|
+
font-weight: 400;
|
|
4619
|
+
opacity: 0.8;
|
|
4620
|
+
transition:
|
|
4621
|
+
opacity 0.3s ease,
|
|
4622
|
+
transform 0.5s cubic-bezier(0.41, 0, 0.12, 0.99),
|
|
4623
|
+
filter 0.3s ease;
|
|
4624
|
+
transform-origin: left;
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
.lyrics-footer.lyrics-line {
|
|
4628
|
+
font-size: 1.2em;
|
|
4629
|
+
padding: 20px var(--lyplus-padding-line) 50vh var(--lyplus-padding-line);
|
|
4630
|
+
cursor: default;
|
|
4631
|
+
}
|
|
4632
|
+
|
|
4633
|
+
.lyrics-footer.active {
|
|
4634
|
+
opacity: 1;
|
|
4635
|
+
color: rgba(255, 255, 255, 0.5); /* Grey instead of primary */
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
.lyrics-footer.scroll-animate {
|
|
4639
|
+
transition: none !important;
|
|
4640
|
+
animation-name: lyrics-scroll;
|
|
4641
|
+
animation-duration: var(--scroll-duration, 280ms);
|
|
4642
|
+
animation-timing-function: cubic-bezier(0.41, 0, 0.12, 0.99);
|
|
4643
|
+
animation-fill-mode: both;
|
|
4644
|
+
animation-delay: var(--lyrics-line-delay, 0ms);
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
.lyrics-container.blur-inactive-enabled:not(.not-focused)
|
|
4648
|
+
.lyrics-footer:not(.active) {
|
|
4649
|
+
filter: blur(var(--lyplus-blur-amount));
|
|
4650
|
+
opacity: 0.5;
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
.lyrics-container.user-scrolling .lyrics-footer {
|
|
4654
|
+
transition: none !important;
|
|
4655
|
+
filter: none !important;
|
|
4656
|
+
opacity: 0.8 !important;
|
|
4526
4657
|
}
|
|
4527
4658
|
|
|
4528
4659
|
.lyrics-footer p {
|
|
@@ -4530,12 +4661,14 @@ AmLyrics$1.styles = i$3 `
|
|
|
4530
4661
|
}
|
|
4531
4662
|
|
|
4532
4663
|
.lyrics-footer a {
|
|
4533
|
-
color:
|
|
4534
|
-
text-
|
|
4664
|
+
color: var(--lyplus-text-primary); /* Stand out using primary color */
|
|
4665
|
+
text-underline-offset: 2px;
|
|
4666
|
+
opacity: 0.8;
|
|
4667
|
+
transition: opacity 0.2s;
|
|
4535
4668
|
}
|
|
4536
4669
|
|
|
4537
4670
|
.lyrics-footer a:hover {
|
|
4538
|
-
|
|
4671
|
+
opacity: 1;
|
|
4539
4672
|
}
|
|
4540
4673
|
|
|
4541
4674
|
.footer-content {
|
|
@@ -4659,6 +4792,7 @@ AmLyrics$1.styles = i$3 `
|
|
|
4659
4792
|
|
|
4660
4793
|
.lyrics-romanization-container.rtl-text {
|
|
4661
4794
|
direction: rtl !important;
|
|
4795
|
+
text-align: right;
|
|
4662
4796
|
}
|
|
4663
4797
|
|
|
4664
4798
|
.lyrics-romanization-container .lyrics-syllable {
|
|
@@ -4872,23 +5006,22 @@ AmLyrics$1.styles = i$3 `
|
|
|
4872
5006
|
/* Gap dot animations */
|
|
4873
5007
|
@keyframes gap-loop {
|
|
4874
5008
|
from {
|
|
4875
|
-
transform: scale(1.12);
|
|
5009
|
+
transform: translateY(-25%) scale(1.12);
|
|
4876
5010
|
}
|
|
4877
5011
|
to {
|
|
4878
|
-
transform: scale(var(--gap-exit-scale, 0.85));
|
|
5012
|
+
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85));
|
|
4879
5013
|
}
|
|
4880
5014
|
}
|
|
4881
5015
|
|
|
4882
5016
|
@keyframes gap-ended {
|
|
4883
5017
|
0% {
|
|
4884
|
-
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85))
|
|
4885
|
-
translateZ(0);
|
|
5018
|
+
transform: translateY(-25%) scale(var(--gap-exit-scale, 0.85));
|
|
4886
5019
|
}
|
|
4887
5020
|
35% {
|
|
4888
|
-
transform: translateY(-
|
|
5021
|
+
transform: translateY(-25%) scale(1.2);
|
|
4889
5022
|
}
|
|
4890
5023
|
100% {
|
|
4891
|
-
transform: translateY(-25%) scale(0)
|
|
5024
|
+
transform: translateY(-25%) scale(0);
|
|
4892
5025
|
}
|
|
4893
5026
|
}
|
|
4894
5027
|
|
|
@@ -4905,17 +5038,18 @@ AmLyrics$1.styles = i$3 `
|
|
|
4905
5038
|
reflow in between) to reliably restart the animation each time */
|
|
4906
5039
|
@keyframes lyrics-scroll {
|
|
4907
5040
|
from {
|
|
4908
|
-
transform:
|
|
5041
|
+
transform: translate3d(0, var(--scroll-delta), 0);
|
|
4909
5042
|
}
|
|
4910
5043
|
to {
|
|
4911
|
-
transform:
|
|
5044
|
+
transform: translate3d(0, 0, 0);
|
|
4912
5045
|
}
|
|
4913
5046
|
}
|
|
4914
5047
|
|
|
4915
|
-
/* Character grow animation
|
|
5048
|
+
/* Character grow animation — translate3d+scale3d for smooth transform,
|
|
5049
|
+
drop-shadow for glow (text-shadow doesn't work with background-clip:text) */
|
|
4916
5050
|
@keyframes grow-dynamic {
|
|
4917
5051
|
0% {
|
|
4918
|
-
transform:
|
|
5052
|
+
transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
|
|
4919
5053
|
filter: drop-shadow(
|
|
4920
5054
|
0 0 0
|
|
4921
5055
|
color-mix(in srgb, var(--lyplus-lyrics-palette), transparent 100%)
|
|
@@ -4923,27 +5057,12 @@ AmLyrics$1.styles = i$3 `
|
|
|
4923
5057
|
}
|
|
4924
5058
|
25%,
|
|
4925
5059
|
30% {
|
|
4926
|
-
transform:
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
calc(var(--max-scale) * calc(var(--lyplus-font-size-base-grow) / 25)),
|
|
4933
|
-
0,
|
|
4934
|
-
0,
|
|
4935
|
-
0,
|
|
4936
|
-
0,
|
|
4937
|
-
1,
|
|
4938
|
-
0,
|
|
4939
|
-
calc(
|
|
4940
|
-
var(--char-offset-x, 0) *
|
|
4941
|
-
calc(var(--lyplus-font-size-base-grow) / 25)
|
|
4942
|
-
),
|
|
4943
|
-
var(--translate-y-peak, -2),
|
|
4944
|
-
0,
|
|
4945
|
-
1
|
|
4946
|
-
);
|
|
5060
|
+
transform: translate3d(
|
|
5061
|
+
var(--char-offset-x, 0px),
|
|
5062
|
+
var(--translate-y-peak, -2px),
|
|
5063
|
+
0
|
|
5064
|
+
)
|
|
5065
|
+
scale3d(var(--matrix-scale, 1.1), var(--matrix-scale, 1.1), 1);
|
|
4947
5066
|
filter: drop-shadow(
|
|
4948
5067
|
0 0 0.1em
|
|
4949
5068
|
color-mix(
|
|
@@ -4953,8 +5072,10 @@ AmLyrics$1.styles = i$3 `
|
|
|
4953
5072
|
)
|
|
4954
5073
|
);
|
|
4955
5074
|
}
|
|
5075
|
+
75%,
|
|
4956
5076
|
100% {
|
|
4957
|
-
transform:
|
|
5077
|
+
transform: translate3d(0, var(--char-rise-y, -1.12px), 0)
|
|
5078
|
+
scale3d(1, 1, 1);
|
|
4958
5079
|
filter: drop-shadow(
|
|
4959
5080
|
0 0 0
|
|
4960
5081
|
color-mix(in srgb, var(--lyplus-lyrics-palette), transparent 100%)
|
|
@@ -5086,15 +5207,15 @@ __decorate([
|
|
|
5086
5207
|
__decorate([
|
|
5087
5208
|
n({ type: String, attribute: 'song-album' })
|
|
5088
5209
|
], AmLyrics$1.prototype, "songAlbum", void 0);
|
|
5210
|
+
__decorate([
|
|
5211
|
+
n({ type: String, attribute: 'songwriters' })
|
|
5212
|
+
], AmLyrics$1.prototype, "songwriters", void 0);
|
|
5089
5213
|
__decorate([
|
|
5090
5214
|
n({ type: Number, attribute: 'song-duration' })
|
|
5091
5215
|
], AmLyrics$1.prototype, "songDurationMs", void 0);
|
|
5092
5216
|
__decorate([
|
|
5093
5217
|
n({ type: String, attribute: 'highlight-color' })
|
|
5094
5218
|
], AmLyrics$1.prototype, "highlightColor", void 0);
|
|
5095
|
-
__decorate([
|
|
5096
|
-
n({ type: String, attribute: 'hover-background-color' })
|
|
5097
|
-
], AmLyrics$1.prototype, "hoverBackgroundColor", void 0);
|
|
5098
5219
|
__decorate([
|
|
5099
5220
|
n({ type: String, attribute: 'font-family' })
|
|
5100
5221
|
], AmLyrics$1.prototype, "fontFamily", void 0);
|