mr-magic-mcp-server 0.3.9 → 0.3.10
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/package.json +1 -1
- package/src/providers/lrclib.js +25 -6
package/package.json
CHANGED
package/src/providers/lrclib.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
|
|
3
|
-
import { normalizeLyricRecord } from '../provider-result-schema.js';
|
|
3
|
+
import { normalizeLyricRecord, lyricContentScore } from '../provider-result-schema.js';
|
|
4
4
|
import { createLogger } from '../utils/logger.js';
|
|
5
5
|
|
|
6
6
|
const logger = createLogger('provider:lrclib');
|
|
@@ -40,6 +40,22 @@ async function querySearch(track) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Pick the best candidate from a list: prefer synced over plain, then prefer
|
|
45
|
+
* richer lyric content. This ensures fetchFromLrclib always returns a synced
|
|
46
|
+
* result when one is available rather than the first incidentally-ordered one.
|
|
47
|
+
*/
|
|
48
|
+
function chooseBestCandidate(candidates) {
|
|
49
|
+
if (!candidates.length) return null;
|
|
50
|
+
return candidates.slice().sort((a, b) => {
|
|
51
|
+
// Synced results come first
|
|
52
|
+
const syncedDiff = (b.synced ? 1 : 0) - (a.synced ? 1 : 0);
|
|
53
|
+
if (syncedDiff !== 0) return syncedDiff;
|
|
54
|
+
// Among equally-synced results, prefer richer content
|
|
55
|
+
return lyricContentScore(b) - lyricContentScore(a);
|
|
56
|
+
})[0];
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
export async function fetchFromLrclib(track) {
|
|
44
60
|
try {
|
|
45
61
|
const results = await querySearch(track);
|
|
@@ -47,16 +63,19 @@ export async function fetchFromLrclib(track) {
|
|
|
47
63
|
logger.debug('LRCLIB: no results found', { track });
|
|
48
64
|
return null;
|
|
49
65
|
}
|
|
50
|
-
const
|
|
66
|
+
const exactMatches = results.filter((record) => {
|
|
51
67
|
const sameTitle = record.title?.toLowerCase() === track.title?.toLowerCase();
|
|
52
68
|
const sameArtist = record.artist?.toLowerCase() === track.artist?.toLowerCase();
|
|
53
69
|
return sameTitle && sameArtist;
|
|
54
70
|
});
|
|
55
|
-
|
|
71
|
+
// Prefer exact matches; if none, fall back to all results.
|
|
72
|
+
// Within each group, prefer synced then richer content.
|
|
73
|
+
const result = chooseBestCandidate(exactMatches) ?? chooseBestCandidate(results);
|
|
56
74
|
logger.debug('LRCLIB: match selected', {
|
|
57
|
-
exact:
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
exact: exactMatches.length > 0,
|
|
76
|
+
synced: result?.synced,
|
|
77
|
+
title: result?.title,
|
|
78
|
+
artist: result?.artist
|
|
60
79
|
});
|
|
61
80
|
return result;
|
|
62
81
|
} catch (error) {
|