Skip to content

Commit 042e585

Browse files
committed
feat(applemusic, spotify): enhance best match scoring logic and improve token handling
1 parent 637c7b5 commit 042e585

File tree

2 files changed

+42
-28
lines changed

2 files changed

+42
-28
lines changed

src/sources/applemusic.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,8 @@ export default class AppleMusicSource {
540540
duration,
541541
decodedTrack,
542542
isExplicit,
543-
this.allowExplicit
543+
this.allowExplicit,
544+
false
544545
)
545546
if (!bestMatch) {
546547
return {
@@ -563,7 +564,7 @@ export default class AppleMusicSource {
563564
return searchQuery
564565
}
565566

566-
async _findBestMatch(list, target, original, isExplicit, allowExplicit) {
567+
async _findBestMatch(list, target, original, isExplicit, allowExplicit, retried = false) {
567568
const allowedDurationDiff = target * DURATION_TOLERANCE
568569
const normalizedOriginalTitle = this._normalize(original.title)
569570
const normalizedOriginalAuthor = this._normalize(original.author)
@@ -577,9 +578,16 @@ export default class AppleMusicSource {
577578
const normalizedItemAuthor = this._normalize(item.info.author)
578579
let score = 0
579580

580-
if (!normalizedItemTitle.includes(normalizedOriginalTitle)) {
581-
return { item, score: -1 }
581+
const originalTitleWords = new Set(normalizedOriginalTitle.split(' ').filter(w => w.length > 0));
582+
const itemTitleWords = new Set(normalizedItemTitle.split(' ').filter(w => w.length > 0));
583+
584+
let titleScore = 0;
585+
for (const word of originalTitleWords) {
586+
if (itemTitleWords.has(word)) {
587+
titleScore++;
588+
}
582589
}
590+
score += titleScore * 100;
583591

584592
const authorSimilarity = this._calculateSimilarity(
585593
normalizedOriginalAuthor,
@@ -588,9 +596,9 @@ export default class AppleMusicSource {
588596
score += authorSimilarity * 100
589597

590598
const titleWords = new Set(normalizedItemTitle.split(' '))
591-
const originalTitleWords = new Set(normalizedOriginalTitle.split(' '))
599+
const originalTitleWordsSet = new Set(normalizedOriginalTitle.split(' '))
592600
const extraWords = [...titleWords].filter(
593-
(word) => !originalTitleWords.has(word)
601+
(word) => !originalTitleWordsSet.has(word)
594602
)
595603
score -= extraWords.length * 5
596604

@@ -613,13 +621,17 @@ export default class AppleMusicSource {
613621
return { item, score }
614622
}).filter((c) => c.score >= 0)
615623

616-
if (scoredCandidates.length === 0) {
624+
if (scoredCandidates.length === 0 && !retried) {
617625
const newSearch = await this.nodelink.sources.searchWithDefault(`${original.title} ${original.author} official video`);
618626
if (newSearch.loadType !== 'search' || newSearch.data.length === 0) {
619627
return null;
620628
}
621629

622-
return await this._findBestMatch(newSearch.data, target, original, isExplicit, allowExplicit);
630+
return await this._findBestMatch(newSearch.data, target, original, isExplicit, allowExplicit, true);
631+
}
632+
633+
if (scoredCandidates.length === 0) {
634+
return null;
623635
}
624636

625637
scoredCandidates.sort((a, b) => b.score - a.score)
@@ -631,6 +643,8 @@ export default class AppleMusicSource {
631643
if (!text) return ''
632644
return text
633645
.toLowerCase()
646+
.replace(/feat\.?/g, '')
647+
.replace(/ft\.?/g, '')
634648
.replace(/[^\w\s]/g, '')
635649
.trim()
636650
}

src/sources/spotify.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ export default class SpotifySource {
509509
return searchQuery
510510
}
511511

512-
async _findBestMatch(list, target, original, isExplicit, allowExplicit) {
512+
async _findBestMatch(list, target, original, isExplicit, allowExplicit, retried = false) {
513513
const allowedDurationDiff = target * DURATION_TOLERANCE
514514
const normalizedOriginalTitle = this._normalize(original.title)
515515
const normalizedOriginalAuthor = this._normalize(original.author)
@@ -523,23 +523,17 @@ export default class SpotifySource {
523523
const normalizedItemAuthor = this._normalize(item.info.author)
524524
let score = 0
525525

526-
if (normalizedItemTitle === normalizedOriginalTitle) {
527-
score += 500
528-
} else if (normalizedItemTitle.includes(normalizedOriginalTitle)) {
529-
score += 200
530-
} else if (normalizedOriginalTitle.includes(normalizedItemTitle)) {
531-
score += 100
532-
} else {
533-
const titleSimilarity = this._calculateSimilarity(
534-
normalizedOriginalTitle,
535-
normalizedItemTitle
536-
)
537-
if (titleSimilarity > 0.7) {
538-
score += titleSimilarity * 50
539-
} else {
540-
return { item, score: -1 }
526+
const originalTitleWords = new Set(normalizedOriginalTitle.split(' ').filter(w => w.length > 0));
527+
const itemTitleWords = new Set(normalizedItemTitle.split(' ').filter(w => w.length > 0));
528+
529+
let titleScore = 0;
530+
for (const word of originalTitleWords) {
531+
if (itemTitleWords.has(word)) {
532+
titleScore++;
541533
}
542534
}
535+
score += titleScore * 100;
536+
543537

544538
const originalArtists = normalizedOriginalAuthor.split(/,\s*|\s+&\s+/).map(a => a.trim()).filter(Boolean);
545539
let authorMatchScore = 0;
@@ -559,9 +553,9 @@ export default class SpotifySource {
559553
}
560554

561555
const titleWords = new Set(normalizedItemTitle.split(' '))
562-
const originalTitleWords = new Set(normalizedOriginalTitle.split(' '))
556+
const originalTitleWordsSet = new Set(normalizedOriginalTitle.split(' '))
563557
const extraWords = [...titleWords].filter(
564-
(word) => !originalTitleWords.has(word)
558+
(word) => !originalTitleWordsSet.has(word)
565559
)
566560
score -= extraWords.length * 5
567561

@@ -584,13 +578,17 @@ export default class SpotifySource {
584578
return { item, score }
585579
}).filter((c) => c.score >= 0)
586580

587-
if (scoredCandidates.length === 0) {
581+
if (scoredCandidates.length === 0 && !retried) {
588582
const newSearch = await this.nodelink.sources.searchWithDefault(`${original.title} ${original.author} official video`);
589583
if (newSearch.loadType !== 'search' || newSearch.data.length === 0) {
590584
return null;
591585
}
592586

593-
return await this._findBestMatch(newSearch.data, target, original, isExplicit, allowExplicit);
587+
return await this._findBestMatch(newSearch.data, target, original, isExplicit, allowExplicit, true);
588+
}
589+
590+
if (scoredCandidates.length === 0) {
591+
return null;
594592
}
595593

596594
scoredCandidates.sort((a, b) => b.score - a.score)
@@ -601,6 +599,8 @@ export default class SpotifySource {
601599
_normalize(str) {
602600
return str
603601
.toLowerCase()
602+
.replace(/feat\.?/g, '')
603+
.replace(/ft\.?/g, '')
604604
.replace(/[^\w\s]/g, '')
605605
.trim()
606606
}

0 commit comments

Comments
 (0)