✨ feat(aniwatch): Improves title matching logic
- Enhances title matching accuracy when fetching Aniwatch IDs. - Prioritizes user-preferred titles and falls back to English titles. - Ensures only one fetch call is made per title if both english and userPreferred title are same. - Adds a score threshold to filter low-quality matches. - Fixes a bug where the episode list was not being returned.
This commit is contained in:
@@ -119,17 +119,43 @@ async function fetchEpisodes(
|
||||
});
|
||||
}
|
||||
|
||||
// function updateTitles(title: Partial<{ english: string; userPreferred: string }>) {
|
||||
// const english = title.english?.toLowerCase();
|
||||
// const userPreferred = title.userPreferred?.toLowerCase();
|
||||
|
||||
// if (english?.match(/my hero academia.+[0-9]$/)) {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
function getAniwatchId(
|
||||
animeTitle: Partial<{ english: string; userPreferred: string }>,
|
||||
): Promise<string | undefined> {
|
||||
return Promise.allSettled([
|
||||
animeTitle = {
|
||||
english: animeTitle?.english?.toLowerCase(),
|
||||
userPreferred: animeTitle?.userPreferred?.toLowerCase(),
|
||||
};
|
||||
const promises = [];
|
||||
if (animeTitle.userPreferred) {
|
||||
promises.push(
|
||||
fetch(
|
||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(animeTitle.english!)}`,
|
||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(
|
||||
animeTitle.userPreferred,
|
||||
)}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (animeTitle.english && animeTitle.english !== animeTitle.userPreferred) {
|
||||
promises.push(
|
||||
fetch(
|
||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(animeTitle.userPreferred!)}`,
|
||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(
|
||||
animeTitle.english,
|
||||
)}`,
|
||||
),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.allSettled(promises)
|
||||
.then((responses) => {
|
||||
return responses.reduce(
|
||||
async (current, res) => {
|
||||
@@ -164,16 +190,21 @@ function getAniwatchId(
|
||||
return;
|
||||
}
|
||||
|
||||
const bestMatchingTitle = findBestMatchingTitle(
|
||||
const { title: bestMatchingTitle, score } = findBestMatchingTitle(
|
||||
animeTitle,
|
||||
animes.map((anime) => ({
|
||||
english: anime.name,
|
||||
userPreferred: anime.jname,
|
||||
})),
|
||||
);
|
||||
if (score < 0.8) {
|
||||
return;
|
||||
}
|
||||
|
||||
return animes.find(
|
||||
(anime) =>
|
||||
anime.name === bestMatchingTitle || anime.jname === bestMatchingTitle,
|
||||
anime.name?.toLowerCase() === bestMatchingTitle ||
|
||||
anime.jname?.toLowerCase() === bestMatchingTitle,
|
||||
)?.id;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,18 +81,23 @@ export function fetchEpisodes(
|
||||
app.openapi(route, async (c) => {
|
||||
const aniListId = Number(c.req.param("aniListId"));
|
||||
|
||||
const { result: episodes, errorOccurred } = await fetchEpisodes(
|
||||
const { result, errorOccurred } = await fetchEpisodes(
|
||||
aniListId,
|
||||
env(c, "workerd"),
|
||||
);
|
||||
|
||||
if (errorOccurred) {
|
||||
if (errorOccurred || !result) {
|
||||
return c.json(ErrorResponse, { status: 500 });
|
||||
}
|
||||
|
||||
const { episodes, providerId } = result;
|
||||
if (!episodes || episodes.length === 0) {
|
||||
return c.json(ErrorResponse, { status: 404 });
|
||||
}
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
result: episodes ?? [],
|
||||
result: { providerId, episodes },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,17 +1,40 @@
|
||||
function findBestMatch(mainString: string, targets: string[]): string | null {
|
||||
if (targets.length === 0) return null;
|
||||
if (targets.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (targets.length === 1) {
|
||||
return targets[0];
|
||||
}
|
||||
|
||||
let bestMatch = targets[0];
|
||||
let highestScore = stringMatchingAlgorithm(mainString, bestMatch);
|
||||
|
||||
for (let i = 1; i < targets.length; i++) {
|
||||
const currentScore = stringMatchingAlgorithm(mainString, targets[i]);
|
||||
if (currentScore === 1) {
|
||||
bestMatch = targets[i];
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(
|
||||
"searching best match",
|
||||
`'${mainString}'`,
|
||||
`'${targets[i]}'`,
|
||||
currentScore,
|
||||
highestScore,
|
||||
);
|
||||
if (currentScore > highestScore) {
|
||||
highestScore = currentScore;
|
||||
bestMatch = targets[i];
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
"findBestMatch",
|
||||
`'${mainString}'`,
|
||||
`'${bestMatch}'`,
|
||||
highestScore,
|
||||
);
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
@@ -23,23 +46,39 @@ type Title = {
|
||||
export const findBestMatchingTitle = (
|
||||
title: Partial<Title>,
|
||||
titlesToSearch: Partial<Title>[],
|
||||
): string | null => {
|
||||
): { title: string | null; score: number } => {
|
||||
const { english, userPreferred } = title;
|
||||
|
||||
let match;
|
||||
let expectedSuffix = "";
|
||||
if ((match = english?.match(/my hero academia.+([0-9])$/))) {
|
||||
expectedSuffix = match[1];
|
||||
}
|
||||
|
||||
console.log("searching best user preferred title", userPreferred);
|
||||
const userPreferredBestMatch = userPreferred
|
||||
? findBestMatch(
|
||||
userPreferred,
|
||||
titlesToSearch
|
||||
.map((title) => title.userPreferred)
|
||||
.filter((title) => title !== undefined),
|
||||
.map((title) => title.userPreferred?.toLowerCase())
|
||||
.filter(
|
||||
(title) =>
|
||||
title !== undefined &&
|
||||
(!expectedSuffix || title.endsWith(expectedSuffix)),
|
||||
),
|
||||
)
|
||||
: null;
|
||||
console.log("searching best english title", english);
|
||||
const englishBestMatch = english
|
||||
? findBestMatch(
|
||||
english,
|
||||
titlesToSearch
|
||||
.map((title) => title.english)
|
||||
.filter((title) => title !== undefined),
|
||||
.map((title) => title.english?.toLowerCase())
|
||||
.filter(
|
||||
(title) =>
|
||||
title !== undefined &&
|
||||
(!expectedSuffix || title.endsWith(expectedSuffix)),
|
||||
),
|
||||
)
|
||||
: null;
|
||||
|
||||
@@ -54,10 +93,10 @@ export const findBestMatchingTitle = (
|
||||
console.log(title.userPreferred, userPreferredScore);
|
||||
if (userPreferredScore >= englishScore) {
|
||||
console.log("User preferred", userPreferredBestMatch);
|
||||
return userPreferredBestMatch;
|
||||
return { title: userPreferredBestMatch, score: userPreferredScore };
|
||||
} else {
|
||||
console.log("English", englishBestMatch);
|
||||
return englishBestMatch;
|
||||
return { title: englishBestMatch, score: englishScore };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user