✨ 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(
|
function getAniwatchId(
|
||||||
animeTitle: Partial<{ english: string; userPreferred: string }>,
|
animeTitle: Partial<{ english: string; userPreferred: string }>,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
return Promise.allSettled([
|
animeTitle = {
|
||||||
fetch(
|
english: animeTitle?.english?.toLowerCase(),
|
||||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(animeTitle.english!)}`,
|
userPreferred: animeTitle?.userPreferred?.toLowerCase(),
|
||||||
),
|
};
|
||||||
fetch(
|
const promises = [];
|
||||||
`https://aniwatch.up.railway.app/api/v2/hianime/search?q=${encodeURIComponent(animeTitle.userPreferred!)}`,
|
if (animeTitle.userPreferred) {
|
||||||
),
|
promises.push(
|
||||||
])
|
fetch(
|
||||||
|
`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.english,
|
||||||
|
)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.allSettled(promises)
|
||||||
.then((responses) => {
|
.then((responses) => {
|
||||||
return responses.reduce(
|
return responses.reduce(
|
||||||
async (current, res) => {
|
async (current, res) => {
|
||||||
@@ -164,16 +190,21 @@ function getAniwatchId(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bestMatchingTitle = findBestMatchingTitle(
|
const { title: bestMatchingTitle, score } = findBestMatchingTitle(
|
||||||
animeTitle,
|
animeTitle,
|
||||||
animes.map((anime) => ({
|
animes.map((anime) => ({
|
||||||
english: anime.name,
|
english: anime.name,
|
||||||
userPreferred: anime.jname,
|
userPreferred: anime.jname,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
if (score < 0.8) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return animes.find(
|
return animes.find(
|
||||||
(anime) =>
|
(anime) =>
|
||||||
anime.name === bestMatchingTitle || anime.jname === bestMatchingTitle,
|
anime.name?.toLowerCase() === bestMatchingTitle ||
|
||||||
|
anime.jname?.toLowerCase() === bestMatchingTitle,
|
||||||
)?.id;
|
)?.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,18 +81,23 @@ export function fetchEpisodes(
|
|||||||
app.openapi(route, async (c) => {
|
app.openapi(route, async (c) => {
|
||||||
const aniListId = Number(c.req.param("aniListId"));
|
const aniListId = Number(c.req.param("aniListId"));
|
||||||
|
|
||||||
const { result: episodes, errorOccurred } = await fetchEpisodes(
|
const { result, errorOccurred } = await fetchEpisodes(
|
||||||
aniListId,
|
aniListId,
|
||||||
env(c, "workerd"),
|
env(c, "workerd"),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (errorOccurred) {
|
if (errorOccurred || !result) {
|
||||||
return c.json(ErrorResponse, { status: 500 });
|
return c.json(ErrorResponse, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { episodes, providerId } = result;
|
||||||
|
if (!episodes || episodes.length === 0) {
|
||||||
|
return c.json(ErrorResponse, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
success: true,
|
success: true,
|
||||||
result: episodes ?? [],
|
result: { providerId, episodes },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,40 @@
|
|||||||
function findBestMatch(mainString: string, targets: string[]): string | null {
|
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 bestMatch = targets[0];
|
||||||
let highestScore = stringMatchingAlgorithm(mainString, bestMatch);
|
let highestScore = stringMatchingAlgorithm(mainString, bestMatch);
|
||||||
|
|
||||||
for (let i = 1; i < targets.length; i++) {
|
for (let i = 1; i < targets.length; i++) {
|
||||||
const currentScore = stringMatchingAlgorithm(mainString, targets[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) {
|
if (currentScore > highestScore) {
|
||||||
highestScore = currentScore;
|
highestScore = currentScore;
|
||||||
bestMatch = targets[i];
|
bestMatch = targets[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"findBestMatch",
|
||||||
|
`'${mainString}'`,
|
||||||
|
`'${bestMatch}'`,
|
||||||
|
highestScore,
|
||||||
|
);
|
||||||
return bestMatch;
|
return bestMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,23 +46,39 @@ type Title = {
|
|||||||
export const findBestMatchingTitle = (
|
export const findBestMatchingTitle = (
|
||||||
title: Partial<Title>,
|
title: Partial<Title>,
|
||||||
titlesToSearch: Partial<Title>[],
|
titlesToSearch: Partial<Title>[],
|
||||||
): string | null => {
|
): { title: string | null; score: number } => {
|
||||||
const { english, userPreferred } = title;
|
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
|
const userPreferredBestMatch = userPreferred
|
||||||
? findBestMatch(
|
? findBestMatch(
|
||||||
userPreferred,
|
userPreferred,
|
||||||
titlesToSearch
|
titlesToSearch
|
||||||
.map((title) => title.userPreferred)
|
.map((title) => title.userPreferred?.toLowerCase())
|
||||||
.filter((title) => title !== undefined),
|
.filter(
|
||||||
|
(title) =>
|
||||||
|
title !== undefined &&
|
||||||
|
(!expectedSuffix || title.endsWith(expectedSuffix)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
console.log("searching best english title", english);
|
||||||
const englishBestMatch = english
|
const englishBestMatch = english
|
||||||
? findBestMatch(
|
? findBestMatch(
|
||||||
english,
|
english,
|
||||||
titlesToSearch
|
titlesToSearch
|
||||||
.map((title) => title.english)
|
.map((title) => title.english?.toLowerCase())
|
||||||
.filter((title) => title !== undefined),
|
.filter(
|
||||||
|
(title) =>
|
||||||
|
title !== undefined &&
|
||||||
|
(!expectedSuffix || title.endsWith(expectedSuffix)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@@ -54,10 +93,10 @@ export const findBestMatchingTitle = (
|
|||||||
console.log(title.userPreferred, userPreferredScore);
|
console.log(title.userPreferred, userPreferredScore);
|
||||||
if (userPreferredScore >= englishScore) {
|
if (userPreferredScore >= englishScore) {
|
||||||
console.log("User preferred", userPreferredBestMatch);
|
console.log("User preferred", userPreferredBestMatch);
|
||||||
return userPreferredBestMatch;
|
return { title: userPreferredBestMatch, score: userPreferredScore };
|
||||||
} else {
|
} else {
|
||||||
console.log("English", englishBestMatch);
|
console.log("English", englishBestMatch);
|
||||||
return englishBestMatch;
|
return { title: englishBestMatch, score: englishScore };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user