@uimaxbai/am-lyrics 1.0.8 → 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":"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;YA4DX,cAAc;YAoBd,iBAAiB;YASjB,mBAAmB;IAiGjC,OAAO,CAAC,MAAM,CAAC,kBAAkB;mBAkCZ,uBAAuB;mBA6CvB,wBAAwB;IAsE7C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IA4DhC;;;OAGG;mBACkB,oBAAoB;IA0FzC;;;OAGG;mBACkB,qBAAqB;IAyE1C,OAAO,CAAC,MAAM,CAAC,iBAAiB;IA2JhC,OAAO,CAAC,MAAM,CAAC,cAAc;IAa7B,YAAY;IAkBZ;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAoLtB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC;IAuEjE;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAqC/B,OAAO,CAAC,gBAAgB,CAAgC;IAExD,OAAO,CAAC,aAAa,CAA8C;IAEnE,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,qBAAqB;IAsE7B,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,qBAAqB;IAiC7B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAgC/B,OAAO,CAAC,sBAAsB;IAgE9B,OAAO,CAAC,wBAAwB;IA0ChC,OAAO,CAAC,eAAe;IA4CvB,OAAO,CAAC,eAAe;IA4EvB,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAkBzC,OAAO,CAAC,kBAAkB;IA2C1B,OAAO,CAAC,oBAAoB;IAyB5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoJ1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA+C7B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAiD/B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;IA+JtC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAwC5B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAS7B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuErC,OAAO,CAAC,eAAe;IA4HvB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,YAAY;IA2DpB,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAYlC,OAAO,CAAC,cAAc;IAuCtB,MAAM;CA4qBP"}
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,14 +309,14 @@ class GoogleService {
310
309
  }
311
310
  }
312
311
 
313
- const VERSION = '1.0.8';
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',
316
+ 'https://lyricsplus.atomix.one',
317
+ 'https://lyricsplus-seven.vercel.app',
317
318
  'https://lyricsplus.prjktla.workers.dev',
318
319
  'https://lyrics-plus-backend.vercel.app',
319
- 'https://lyricsplus.onrender.com',
320
- 'https://lyricsplus.prjktla.online',
321
320
  ];
322
321
  const DEFAULT_KPOE_SOURCE_ORDER = 'apple,lyricsplus,musixmatch,spotify,musixmatch-word';
323
322
  const TIDAL_SERVERS = [
@@ -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,8 +684,32 @@ 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;
690
- for (const base of KPOE_SERVERS) {
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;
707
+ // Shuffle servers so we pick a random one first, with all others as fallback
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);
712
+ for (const base of shuffledServers) {
691
713
  const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
692
714
  const url = `${normalizedBase}/v2/lyrics/get?${params.toString()}`;
693
715
  let payload = null;
@@ -708,19 +730,50 @@ class AmLyrics extends i {
708
730
  const sourceLabel = payload?.metadata?.source ||
709
731
  payload?.metadata?.provider ||
710
732
  'LyricsPlus (KPoe)';
733
+ const rank = getRank(sourceLabel, lines);
711
734
  const result = { lines, source: sourceLabel };
712
735
  // If source is Apple, return immediately (best quality)
713
- if (sourceLabel.toLowerCase() === 'apple') {
736
+ if (rank === 1) {
714
737
  return result;
715
738
  }
716
739
  // Otherwise, store as fallback if we don't have one yet
717
- if (!fallbackResult) {
718
- fallbackResult = result;
740
+ if (rank < bestFallbackRank) {
741
+ bestFallbackResult = result;
742
+ bestFallbackRank = rank;
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;
747
+ }
748
+ }
749
+ }
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
+ }
719
769
  }
720
770
  }
721
771
  }
772
+ catch (error) {
773
+ // Explicit QQ fallback failed, ignore and proceed to return whatever we had
774
+ }
722
775
  }
723
- return fallbackResult;
776
+ return bestFallbackResult;
724
777
  }
725
778
  /**
726
779
  * Parse LRC subtitle format into LyricsLine[].
@@ -947,16 +1000,17 @@ class AmLyrics extends i {
947
1000
  personIndexMap.set(agentKey, personIndex);
948
1001
  });
949
1002
  agentEntries.forEach(([agentKey, agentData]) => {
1003
+ const mappedKey = agentData.alias || agentKey;
950
1004
  if (agentData.type === 'group') {
951
- singerAlignmentMap[agentKey] = 'start';
1005
+ singerAlignmentMap[mappedKey] = 'start';
952
1006
  }
953
1007
  else if (agentData.type === 'other') {
954
- singerAlignmentMap[agentKey] = 'end';
1008
+ singerAlignmentMap[mappedKey] = 'end';
955
1009
  }
956
1010
  else if (agentData.type === 'person') {
957
1011
  const personIndex = personIndexMap.get(agentKey);
958
1012
  if (personIndex !== undefined) {
959
- singerAlignmentMap[agentKey] =
1013
+ singerAlignmentMap[mappedKey] =
960
1014
  personIndex % 2 === 0 ? 'start' : 'end';
961
1015
  }
962
1016
  }
@@ -1406,7 +1460,22 @@ class AmLyrics extends i {
1406
1460
  return [];
1407
1461
  const activeLines = [];
1408
1462
  for (let i = 0; i < this.lyrics.length; i += 1) {
1409
- 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) {
1410
1479
  activeLines.push(i);
1411
1480
  }
1412
1481
  }