diff options
| author | Fuwn <[email protected]> | 2026-03-01 13:09:43 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-03-01 13:09:43 -0800 |
| commit | 8aba91a2dcc1db14815f9ef0e25f18026f4abea0 (patch) | |
| tree | 748b4f164486f254180451411fbdbb9b4d1ec422 /src | |
| parent | feat(match): add confidence gate for subtitle title matching (diff) | |
| download | due.moe-8aba91a2dcc1db14815f9ef0e25f18026f4abea0.tar.xz due.moe-8aba91a2dcc1db14815f9ef0e25f18026f4abea0.zip | |
feat(match): skip ambiguous subtitle matches via score margin
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/Media/Anime/Airing/Subtitled/match.ts | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/src/lib/Media/Anime/Airing/Subtitled/match.ts b/src/lib/Media/Anime/Airing/Subtitled/match.ts index dc8dbff9..661d0d23 100644 --- a/src/lib/Media/Anime/Airing/Subtitled/match.ts +++ b/src/lib/Media/Anime/Airing/Subtitled/match.ts @@ -67,6 +67,7 @@ const isMeaningfulToken = (token: string): boolean => const MIN_MATCH_SCORE = 0.3; const MIN_TOKEN_OVERLAP = 2; +const MIN_MATCH_MARGIN = 0.08; interface SimilarityAnalysis { score: number; @@ -124,6 +125,7 @@ export const findClosestMatch = (times: Time[], anime: Media): Time | null => { })); let bestMatch: Time | null = null; let bestScore = 0; + let secondBestScore = 0; let bestTokenOverlap = 0; let bestNumericTokenOverlap = 0; const searchTitles = [anime.title.romaji, anime.title.english, ...anime.synonyms].filter(Boolean); @@ -137,15 +139,19 @@ export const findClosestMatch = (times: Time[], anime: Media): Time | null => { const similarity = calculateWeightedSimilarity(normalizedSearchTitle, normalized); if (similarity.score > bestScore) { + secondBestScore = bestScore; bestScore = similarity.score; bestTokenOverlap = similarity.tokenOverlap; bestNumericTokenOverlap = similarity.numericTokenOverlap; bestMatch = time; + } else if (similarity.score > secondBestScore) { + secondBestScore = similarity.score; } } } if (bestScore < MIN_MATCH_SCORE) return null; + if (bestScore - secondBestScore < MIN_MATCH_MARGIN) return null; if (bestNumericTokenOverlap === 0 && bestTokenOverlap < MIN_TOKEN_OVERLAP) return null; return bestMatch; |