@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.
@@ -1 +1 @@
1
- {"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"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"}
@@ -228,19 +228,18 @@ class GoogleService {
228
228
  line.romanizedText // Skip if already romanized
229
229
  )
230
230
  return line;
231
- // Extract text from syllables
232
- const syllableTexts = line.text.map((s) => s.text);
233
- const romanizedTexts = await this.romanizeTexts(syllableTexts);
234
- const newSyllabus = line.text.map((s, index) => ({
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: romanizedTexts[index]
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: romanizedTexts.join(' '),
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.9';
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 youLyResult = await AmLyrics.fetchLyricsFromYouLyPlus(resolvedMetadata.metadata);
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
- const title = metadata.title?.trim();
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
- let fallbackResult = null;
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
- const shuffledServers = [...KPOE_SERVERS].sort(() => Math.random() - 0.5);
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 (sourceLabel.toLowerCase() === 'apple') {
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 (!fallbackResult) {
720
- fallbackResult = result;
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
- return fallbackResult;
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[agentKey] = 'start';
1005
+ singerAlignmentMap[mappedKey] = 'start';
954
1006
  }
955
1007
  else if (agentData.type === 'other') {
956
- singerAlignmentMap[agentKey] = 'end';
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[agentKey] =
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
- if (time >= this.lyrics[i].timestamp && time <= this.lyrics[i].endtime) {
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
  }