Update checkmate/checkmate.js

This commit is contained in:
aka paul 2025-11-28 19:06:37 +00:00
parent ac2ff67c14
commit b3d8ebbfb3

View file

@ -1,6 +1,6 @@
//Thanks ibro for the TMDB search! // Credits for Search, Details, and Episodes functions to ibro, with impromements made by me
async function searchResults(keyword) { async function searchResults(query) {
try { try {
let transformedResults = []; let transformedResults = [];
@ -14,29 +14,152 @@ async function searchResults(keyword) {
const skipTitleFilter = Object.values(keywordGroups).flat(); const skipTitleFilter = Object.values(keywordGroups).flat();
const shouldFilter = !matchesKeyword(keyword, skipTitleFilter); const shouldFilter = !matchesKeyword(query, skipTitleFilter);
const encodedKeyword = encodeURIComponent(keyword); const encodedQuery = encodeURIComponent(query);
let baseUrl = null; let baseUrl = null;
if (matchesKeyword(keyword, keywordGroups.trending)) { if (matchesKeyword(query, keywordGroups.trending)) {
baseUrl = `https://api.themoviedb.org/3/trending/all/week?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/trending/all/week?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
} else if (matchesKeyword(keyword, keywordGroups.topRatedMovie)) { } else if (matchesKeyword(query, keywordGroups.topRatedMovie)) {
baseUrl = `https://api.themoviedb.org/3/movie/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/movie/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
} else if (matchesKeyword(keyword, keywordGroups.topRatedTV)) { } else if (matchesKeyword(query, keywordGroups.topRatedTV)) {
baseUrl = `https://api.themoviedb.org/3/tv/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/tv/top_rated?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
} else if (matchesKeyword(keyword, keywordGroups.popularMovie)) { } else if (matchesKeyword(query, keywordGroups.popularMovie)) {
baseUrl = `https://api.themoviedb.org/3/movie/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/movie/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
} else if (matchesKeyword(keyword, keywordGroups.popularTV)) { } else if (matchesKeyword(query, keywordGroups.popularTV)) {
baseUrl = `https://api.themoviedb.org/3/tv/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/tv/popular?api_key=9801b6b0548ad57581d111ea690c85c8&include_adult=false&page=`;
} else { } else {
baseUrl = `https://api.themoviedb.org/3/search/multi?api_key=9801b6b0548ad57581d111ea690c85c8&query=${encodedKeyword}&include_adult=false&page=`; baseUrl = `https://api.themoviedb.org/3/search/multi?api_key=9801b6b0548ad57581d111ea690c85c8&query=${encodedQuery}&include_adult=false&page=`;
} }
const fuzzyMatch = (query, title) => {
const q = query.toLowerCase().trim();
const t = title.toLowerCase().trim();
if (t === q) return 1000;
if (t.startsWith(q + ' ') || t.startsWith(q + ':') || t.startsWith(q + '-')) return 950;
const wordBoundaryRegex = new RegExp(`\\b${q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
if (wordBoundaryRegex.test(t)) return 900;
const qTokens = q.split(/\s+/).filter(token => token.length > 0);
const tTokens = t.split(/[\s\-:]+/).filter(token => token.length > 0);
const stopwords = new Set(['the', 'a', 'an', 'and', 'or', 'of', 'in', 'on', 'at', 'to', 'for', 'with']);
let score = 0;
let exactMatches = 0;
let partialMatches = 0;
let significantMatches = 0;
qTokens.forEach(qToken => {
const isStopword = stopwords.has(qToken);
let bestMatch = 0;
let hasExactMatch = false;
tTokens.forEach(tToken => {
let matchScore = 0;
if (tToken === qToken) {
matchScore = isStopword ? 25 : 120;
hasExactMatch = true;
if (!isStopword) significantMatches++;
}
else if (qToken.includes(tToken) && tToken.length >= 3 && qToken.length <= tToken.length + 2) {
matchScore = isStopword ? 8 : 40;
if (!isStopword) significantMatches++;
}
else if (tToken.startsWith(qToken) && qToken.length >= 3) {
matchScore = isStopword ? 12 : 70;
if (!isStopword) significantMatches++;
}
else if (qToken.length >= 4 && tToken.length >= 4) {
const dist = levenshteinDistance(qToken, tToken);
const maxLen = Math.max(qToken.length, tToken.length);
const similarity = 1 - (dist / maxLen);
if (similarity > 0.8) {
matchScore = Math.floor(similarity * 60);
if (!isStopword) significantMatches++;
}
}
bestMatch = Math.max(bestMatch, matchScore);
});
if (bestMatch > 0) {
score += bestMatch;
if (hasExactMatch) exactMatches++;
else partialMatches++;
}
});
const significantTokens = qTokens.filter(t => !stopwords.has(t)).length;
const requiredMatches = Math.max(1, Math.ceil(significantTokens * 0.8));
if (significantMatches < requiredMatches) {
return 0;
}
if (exactMatches + partialMatches >= qTokens.length) {
score += 80;
}
score += exactMatches * 20;
const extraWords = tTokens.length - qTokens.length;
if (extraWords > 2) {
score -= (extraWords - 2) * 25;
}
let orderBonus = 0;
for (let i = 0; i < qTokens.length - 1; i++) {
const currentTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i]));
const nextTokenIndex = tTokens.findIndex(t => t.includes(qTokens[i + 1]));
if (currentTokenIndex !== -1 && nextTokenIndex !== -1 && currentTokenIndex < nextTokenIndex) {
orderBonus += 15;
}
}
score += orderBonus;
return Math.max(0, score);
};
const levenshteinDistance = (a, b) => {
const matrix = [];
for (let i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
for (let j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
for (let i = 1; i <= b.length; i++) {
for (let j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j - 1] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j] + 1
);
}
}
}
return matrix[b.length][a.length];
};
let dataResults = []; let dataResults = [];
if (baseUrl) { if (baseUrl) {
const pagePromises = Array.from({ length: 5 }, (_, i) => const pagePromises = Array.from({ length: 10 }, (_, i) =>
soraFetch(baseUrl + (i + 1)).then(r => r.json()) soraFetch(baseUrl + (i + 1)).then(r => r.json())
); );
const pages = await Promise.all(pagePromises); const pages = await Promise.all(pagePromises);
@ -64,10 +187,20 @@ async function searchResults(keyword) {
.filter(Boolean) .filter(Boolean)
.filter(result => result.title !== "Overflow") .filter(result => result.title !== "Overflow")
.filter(result => result.title !== "My Marriage Partner Is My Student, a Cocky Troublemaker") .filter(result => result.title !== "My Marriage Partner Is My Student, a Cocky Troublemaker")
.filter(r => !shouldFilter || r.title.toLowerCase().includes(keyword.toLowerCase()))
); );
} }
if (shouldFilter) {
const scoredResults = transformedResults.map(r => ({
...r,
score: fuzzyMatch(query, r.title)
}));
transformedResults = scoredResults
.filter(r => r.score > 50)
.sort((a, b) => b.score - a.score)
.map(({ score, ...rest }) => rest);
}
console.log("Transformed Results: " + JSON.stringify(transformedResults)); console.log("Transformed Results: " + JSON.stringify(transformedResults));
return JSON.stringify(transformedResults); return JSON.stringify(transformedResults);
} catch (error) { } catch (error) {