@uimaxbai/am-lyrics 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/AmLyrics.d.ts.map +1 -1
- package/dist/src/am-lyrics.js +92 -25
- package/dist/src/am-lyrics.js.map +1 -1
- package/dist/src/react.js +92 -25
- package/dist/src/react.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/AmLyrics.ts +95 -18
- package/src/GoogleService.ts +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AA2F5C,qBAAa,QAAS,SAAQ,UAAU;IACtC,MAAM,CAAC,MAAM,0BA+mCX;IAGF,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,CAAC,cAAc,CAAmC;IAGzD,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,cAAc,SAAa;IAG3B,oBAAoB,SAA+B;IAGnD,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,UAAU,UAAQ;IAGlB,WAAW,UAAQ;IAGnB,OAAO,CAAC,gBAAgB,CAAS;IAGjC,OAAO,CAAC,eAAe,CAAS;YAElB,kBAAkB;YAKlB,iBAAiB;YAsBjB,iBAAiB;YAKjB,gBAAgB;IAyC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,OAAO,CAAC,YAAY,CAAK;IAEzB,IACI,WAAW,CAAC,KAAK,EAAE,MAAM,EAM5B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAGD,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,MAAM,CAAC,CAAe;IAE9B,OAAO,CAAC,iBAAiB,CAAgB;IAEzC,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,2BAA2B,CAAkC;IAErE,OAAO,CAAC,gBAAgB,CAAkC;IAE1D,OAAO,CAAC,sBAAsB,CAAkC;IAGhE,OAAO,CAAC,YAAY,CAAuB;IAE3C,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,OAAO,CAAC,kBAAkB,CAGZ;IAEd,OAAO,CAAC,wBAAwB,CAGlB;IAGd,OAAO,CAAC,eAAe,CAAC,CAAc;IAEtC,OAAO,CAAC,qBAAqB,CAAuB;IAEpD,OAAO,CAAC,mBAAmB,CAAC,CAAS;IAGrC,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,oBAAoB,CAAS;IAErC,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,gBAAgB,CAAC,CAAgC;IAGzD,OAAO,CAAC,iBAAiB,CAAqB;IAG9C,OAAO,CAAC,aAAa,CAA0B;IAE/C,OAAO,CAAC,wBAAwB,CAA4B;IAE5D,OAAO,CAAC,qBAAqB,CAA4B;IAGzD,OAAO,CAAC,oBAAoB,CAGZ;IAEhB,OAAO,CAAC,mBAAmB,CAAK;IAEhC,OAAO,CAAC,cAAc,CAAqB;IAE3C,OAAO,CAAC,mBAAmB,CAAC,CAAgC;IAE5D,OAAO,CAAC,sBAAsB,CAAC,CAAgC;IAG/D,OAAO,CAAC,eAAe,CAAK;IAE5B,OAAO,CAAC,cAAc,CAA0B;IAEhD,iBAAiB;IAKjB,oBAAoB;YAUN,WAAW;
|
|
1
|
+
{"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"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"}
|
package/dist/src/am-lyrics.js
CHANGED
|
@@ -228,19 +228,18 @@ class GoogleService {
|
|
|
228
228
|
line.romanizedText // Skip if already romanized
|
|
229
229
|
)
|
|
230
230
|
return line;
|
|
231
|
-
//
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
const
|
|
231
|
+
// Get the entire line text to romanize together for context-aware pronunciation
|
|
232
|
+
const fullText = line.text.map((s) => s.text).join('');
|
|
233
|
+
// romanizeTexts expects an array of strings, so we pass an array of one
|
|
234
|
+
const [romanizedFullLine] = await this.romanizeTexts([fullText]);
|
|
235
|
+
const newSyllabus = line.text.map((s) => ({
|
|
235
236
|
...s,
|
|
236
|
-
romanizedText:
|
|
237
|
-
? `${romanizedTexts[index]}`
|
|
238
|
-
: s.text,
|
|
237
|
+
romanizedText: s.romanizedText, // Keep any existing syllabus romanization if provided by API natively
|
|
239
238
|
}));
|
|
240
239
|
return {
|
|
241
240
|
...line,
|
|
242
241
|
text: newSyllabus,
|
|
243
|
-
romanizedText:
|
|
242
|
+
romanizedText: romanizedFullLine || '',
|
|
244
243
|
};
|
|
245
244
|
}));
|
|
246
245
|
}
|
|
@@ -310,7 +309,7 @@ class GoogleService {
|
|
|
310
309
|
}
|
|
311
310
|
}
|
|
312
311
|
|
|
313
|
-
const VERSION = '1.0
|
|
312
|
+
const VERSION = '1.1.0';
|
|
314
313
|
const INSTRUMENTAL_THRESHOLD_MS = 7000; // Show dots for gaps >= 7s
|
|
315
314
|
const KPOE_SERVERS = [
|
|
316
315
|
'https://lyricsplus.binimum.org',
|
|
@@ -471,7 +470,9 @@ class AmLyrics extends i {
|
|
|
471
470
|
!this.songArtist &&
|
|
472
471
|
!this.query;
|
|
473
472
|
if (resolvedMetadata?.metadata && !isMusicIdOnlyRequest) {
|
|
474
|
-
const
|
|
473
|
+
const title = resolvedMetadata.metadata.title?.trim() || '';
|
|
474
|
+
const artist = resolvedMetadata.metadata.artist?.trim() || '';
|
|
475
|
+
const youLyResult = await AmLyrics.fetchLyricsFromYouLyPlus(title, artist, resolvedMetadata.metadata);
|
|
475
476
|
if (youLyResult && youLyResult.lines.length > 0) {
|
|
476
477
|
this.lyrics = youLyResult.lines;
|
|
477
478
|
this.lyricsSource = youLyResult.source ?? 'LyricsPlus (KPoe)';
|
|
@@ -672,12 +673,9 @@ class AmLyrics extends i {
|
|
|
672
673
|
}
|
|
673
674
|
return null;
|
|
674
675
|
}
|
|
675
|
-
static async fetchLyricsFromYouLyPlus(metadata) {
|
|
676
|
-
|
|
677
|
-
const artist = metadata.artist?.trim();
|
|
678
|
-
if (!title || !artist) {
|
|
676
|
+
static async fetchLyricsFromYouLyPlus(title, artist, metadata = {}) {
|
|
677
|
+
if (!title || !artist)
|
|
679
678
|
return null;
|
|
680
|
-
}
|
|
681
679
|
const params = new URLSearchParams({ title, artist });
|
|
682
680
|
if (metadata.album) {
|
|
683
681
|
params.append('album', metadata.album);
|
|
@@ -686,9 +684,31 @@ class AmLyrics extends i {
|
|
|
686
684
|
params.append('duration', Math.round(metadata.durationMs / 1000).toString());
|
|
687
685
|
}
|
|
688
686
|
params.append('source', DEFAULT_KPOE_SOURCE_ORDER);
|
|
689
|
-
|
|
687
|
+
const getRank = (sourceLabel, parsedLines) => {
|
|
688
|
+
const lower = sourceLabel.toLowerCase();
|
|
689
|
+
const hasWordSync = parsedLines.some((line) => line.text && Array.isArray(line.text) && line.text.length > 1);
|
|
690
|
+
const isQQ = lower.includes('qq') || lower.includes('lyricsplus');
|
|
691
|
+
if (lower.includes('apple') && hasWordSync)
|
|
692
|
+
return 1;
|
|
693
|
+
if (isQQ && hasWordSync)
|
|
694
|
+
return 2;
|
|
695
|
+
if (lower.includes('musixmatch') && hasWordSync)
|
|
696
|
+
return 3;
|
|
697
|
+
if (lower.includes('apple') && !hasWordSync)
|
|
698
|
+
return 4;
|
|
699
|
+
if (isQQ && !hasWordSync)
|
|
700
|
+
return 5;
|
|
701
|
+
if (lower.includes('musixmatch') && !hasWordSync)
|
|
702
|
+
return 6;
|
|
703
|
+
return 10;
|
|
704
|
+
};
|
|
705
|
+
let bestFallbackResult = null;
|
|
706
|
+
let bestFallbackRank = 100;
|
|
690
707
|
// Shuffle servers so we pick a random one first, with all others as fallback
|
|
691
|
-
|
|
708
|
+
// Limit to 2 servers to prevent unnecessary API spam when Apple lyrics are missing
|
|
709
|
+
const shuffledServers = [...KPOE_SERVERS]
|
|
710
|
+
.sort(() => Math.random() - 0.5)
|
|
711
|
+
.slice(0, 2);
|
|
692
712
|
for (const base of shuffledServers) {
|
|
693
713
|
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
|
|
694
714
|
const url = `${normalizedBase}/v2/lyrics/get?${params.toString()}`;
|
|
@@ -710,19 +730,50 @@ class AmLyrics extends i {
|
|
|
710
730
|
const sourceLabel = payload?.metadata?.source ||
|
|
711
731
|
payload?.metadata?.provider ||
|
|
712
732
|
'LyricsPlus (KPoe)';
|
|
733
|
+
const rank = getRank(sourceLabel, lines);
|
|
713
734
|
const result = { lines, source: sourceLabel };
|
|
714
735
|
// If source is Apple, return immediately (best quality)
|
|
715
|
-
if (
|
|
736
|
+
if (rank === 1) {
|
|
716
737
|
return result;
|
|
717
738
|
}
|
|
718
739
|
// Otherwise, store as fallback if we don't have one yet
|
|
719
|
-
if (
|
|
720
|
-
|
|
740
|
+
if (rank < bestFallbackRank) {
|
|
741
|
+
bestFallbackResult = result;
|
|
742
|
+
bestFallbackRank = rank;
|
|
721
743
|
}
|
|
744
|
+
// Proxies are identical mirrors; if we got a valid response (even a fallback),
|
|
745
|
+
// there's no reason to query the next proxy because it will return the exact same fallback.
|
|
746
|
+
break;
|
|
722
747
|
}
|
|
723
748
|
}
|
|
724
749
|
}
|
|
725
|
-
|
|
750
|
+
// If we finished the 2-server check and STILL don't have Apple (1) or QQ (2),
|
|
751
|
+
// force an explicit query against lyricsplus.binimum.org looking for QQ
|
|
752
|
+
if (bestFallbackRank > 2) {
|
|
753
|
+
try {
|
|
754
|
+
const qqParams = new URLSearchParams(params);
|
|
755
|
+
qqParams.set('source', 'qq');
|
|
756
|
+
const url = `https://lyricsplus.binimum.org/v2/lyrics/get?${qqParams.toString()}`;
|
|
757
|
+
const response = await fetch(url);
|
|
758
|
+
if (response.ok) {
|
|
759
|
+
const payload = await response.json();
|
|
760
|
+
if (payload) {
|
|
761
|
+
const lines = AmLyrics.convertKPoeLyrics(payload);
|
|
762
|
+
const sourceLabel = payload?.metadata?.source ||
|
|
763
|
+
payload?.metadata?.provider ||
|
|
764
|
+
'LyricsPlus (KPoe)';
|
|
765
|
+
const rank = getRank(sourceLabel, lines || []);
|
|
766
|
+
if (lines && lines.length > 0 && rank < bestFallbackRank) {
|
|
767
|
+
return { lines, source: sourceLabel };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
// Explicit QQ fallback failed, ignore and proceed to return whatever we had
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return bestFallbackResult;
|
|
726
777
|
}
|
|
727
778
|
/**
|
|
728
779
|
* Parse LRC subtitle format into LyricsLine[].
|
|
@@ -949,16 +1000,17 @@ class AmLyrics extends i {
|
|
|
949
1000
|
personIndexMap.set(agentKey, personIndex);
|
|
950
1001
|
});
|
|
951
1002
|
agentEntries.forEach(([agentKey, agentData]) => {
|
|
1003
|
+
const mappedKey = agentData.alias || agentKey;
|
|
952
1004
|
if (agentData.type === 'group') {
|
|
953
|
-
singerAlignmentMap[
|
|
1005
|
+
singerAlignmentMap[mappedKey] = 'start';
|
|
954
1006
|
}
|
|
955
1007
|
else if (agentData.type === 'other') {
|
|
956
|
-
singerAlignmentMap[
|
|
1008
|
+
singerAlignmentMap[mappedKey] = 'end';
|
|
957
1009
|
}
|
|
958
1010
|
else if (agentData.type === 'person') {
|
|
959
1011
|
const personIndex = personIndexMap.get(agentKey);
|
|
960
1012
|
if (personIndex !== undefined) {
|
|
961
|
-
singerAlignmentMap[
|
|
1013
|
+
singerAlignmentMap[mappedKey] =
|
|
962
1014
|
personIndex % 2 === 0 ? 'start' : 'end';
|
|
963
1015
|
}
|
|
964
1016
|
}
|
|
@@ -1408,7 +1460,22 @@ class AmLyrics extends i {
|
|
|
1408
1460
|
return [];
|
|
1409
1461
|
const activeLines = [];
|
|
1410
1462
|
for (let i = 0; i < this.lyrics.length; i += 1) {
|
|
1411
|
-
|
|
1463
|
+
const line = this.lyrics[i];
|
|
1464
|
+
let effectiveEndTime = line.endtime;
|
|
1465
|
+
// Extend the "active" highlight window to abut the next line,
|
|
1466
|
+
// leaving a 500ms gap for breathing/scrolling
|
|
1467
|
+
if (i < this.lyrics.length - 1) {
|
|
1468
|
+
const nextLineStart = this.lyrics[i + 1].timestamp;
|
|
1469
|
+
const gapDuration = nextLineStart - line.endtime;
|
|
1470
|
+
// If the gap is large enough to trigger the breathing dots,
|
|
1471
|
+
// DO NOT extend the highlight. The text should dim when the dots appear.
|
|
1472
|
+
if (gapDuration < INSTRUMENTAL_THRESHOLD_MS) {
|
|
1473
|
+
if (effectiveEndTime < nextLineStart) {
|
|
1474
|
+
effectiveEndTime = Math.max(effectiveEndTime, nextLineStart - 500);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
if (time >= line.timestamp && time <= effectiveEndTime) {
|
|
1412
1479
|
activeLines.push(i);
|
|
1413
1480
|
}
|
|
1414
1481
|
}
|