fix adult search
This commit is contained in:
1 parent
bee6625a9e
commit
bb010e7062
3 files changed
+74
-47
No files matched your search
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Nuvio Providers",
|
"name": "Nuvio Providers",
|
||||||
"version": "1.0.15",
|
"version": "1.0.16",
|
||||||
"scrapers": [
|
"scrapers": [
|
||||||
{
|
{
|
||||||
"id": "bcine",
|
"id": "bcine",
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
"id": "miruro",
|
"id": "miruro",
|
||||||
"name": "Miruro",
|
"name": "Miruro",
|
||||||
"description": "Anime streams from Miruro with subbed and dubbed sources.",
|
"description": "Anime streams from Miruro with subbed and dubbed sources.",
|
||||||
"version": "1.0.7",
|
"version": "1.0.8",
|
||||||
"author": "Jānis L",
|
"author": "Jānis L",
|
||||||
"supportedTypes": [
|
"supportedTypes": [
|
||||||
"movie",
|
"movie",
|
||||||
|
|||||||
+29
-19
@@ -714,12 +714,16 @@ function responseItems(response) {
|
|||||||
function getExternalIds(anime, key) {
|
function getExternalIds(anime, key) {
|
||||||
return asArray(anime && anime.external_ids ? anime.external_ids[key] : null).map((id) => asNumber(id)).filter((id) => id != null);
|
return asArray(anime && anime.external_ids ? anime.external_ids[key] : null).map((id) => asNumber(id)).filter((id) => id != null);
|
||||||
}
|
}
|
||||||
async function searchCatalogAnime(title) {
|
async function searchCatalogAnime(title, includeAdult = false) {
|
||||||
const response = await apiGet("anime", {
|
const query = {
|
||||||
q: title,
|
q: title,
|
||||||
limit: SEARCH_LIMIT,
|
limit: SEARCH_LIMIT,
|
||||||
sort: "-popularity"
|
sort: "-popularity"
|
||||||
});
|
};
|
||||||
|
if (includeAdult) {
|
||||||
|
query.is_adult = true;
|
||||||
|
}
|
||||||
|
const response = await apiGet("anime", query);
|
||||||
return responseItems(response);
|
return responseItems(response);
|
||||||
}
|
}
|
||||||
function matchesAnyAniListId(anime, aniListIds) {
|
function matchesAnyAniListId(anime, aniListIds) {
|
||||||
@@ -744,28 +748,34 @@ function buildSearchTitles(targetMeta, mapping) {
|
|||||||
return title;
|
return title;
|
||||||
}).slice(0, MAX_SEARCH_QUERIES);
|
}).slice(0, MAX_SEARCH_QUERIES);
|
||||||
}
|
}
|
||||||
async function findCatalogAnime(candidateIds, targetId, searchTitles) {
|
function pickCatalogMatch(results, candidateIds, targetId) {
|
||||||
for (const title of searchTitles) {
|
|
||||||
let results;
|
|
||||||
try {
|
|
||||||
results = await searchCatalogAnime(title);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`[Miruro] Catalog search "${title}" failed: ${error.message}`);
|
|
||||||
if (error.status === 403) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
continue;
|
return null;
|
||||||
}
|
}
|
||||||
const exact = results.find((anime) => getExternalIds(anime, "anilist").includes(Number(targetId)));
|
const exact = results.find((anime) => getExternalIds(anime, "anilist").includes(Number(targetId)));
|
||||||
if (exact) {
|
if (exact) {
|
||||||
return exact;
|
return exact;
|
||||||
}
|
}
|
||||||
const candidate = results.find((anime) => matchesAnyAniListId(anime, candidateIds));
|
return results.find((anime) => matchesAnyAniListId(anime, candidateIds)) || null;
|
||||||
if (candidate) {
|
}
|
||||||
return candidate;
|
async function findCatalogAnime(candidateIds, targetId, searchTitles) {
|
||||||
|
for (const includeAdult of [false, true]) {
|
||||||
|
const titles = includeAdult ? searchTitles.slice(0, 3) : searchTitles;
|
||||||
|
for (const title of titles) {
|
||||||
|
let results;
|
||||||
|
try {
|
||||||
|
results = await searchCatalogAnime(title, includeAdult);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`[Miruro] Catalog search "${title}" failed: ${error.message}`);
|
||||||
|
if (error.status === 403) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const match = pickCatalogMatch(results, candidateIds, targetId);
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+43
-26
@@ -285,13 +285,20 @@ function getExternalIds(anime, key) {
|
|||||||
.filter((id) => id != null);
|
.filter((id) => id != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchCatalogAnime(title) {
|
async function searchCatalogAnime(title, includeAdult = false) {
|
||||||
// Miruro rejects search limits above 15 with a generic 400.
|
// Miruro rejects search limits above 15 with a generic 400. Its catalog
|
||||||
const response = await apiGet('anime', {
|
// also hides adult entries unless is_adult=true is requested explicitly.
|
||||||
|
const query = {
|
||||||
q: title,
|
q: title,
|
||||||
limit: SEARCH_LIMIT,
|
limit: SEARCH_LIMIT,
|
||||||
sort: '-popularity'
|
sort: '-popularity'
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (includeAdult) {
|
||||||
|
query.is_adult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await apiGet('anime', query);
|
||||||
|
|
||||||
return responseItems(response);
|
return responseItems(response);
|
||||||
}
|
}
|
||||||
@@ -327,26 +334,9 @@ function buildSearchTitles(targetMeta, mapping) {
|
|||||||
.slice(0, MAX_SEARCH_QUERIES);
|
.slice(0, MAX_SEARCH_QUERIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findCatalogAnime(candidateIds, targetId, searchTitles) {
|
function pickCatalogMatch(results, candidateIds, targetId) {
|
||||||
for (const title of searchTitles) {
|
|
||||||
let results;
|
|
||||||
|
|
||||||
try {
|
|
||||||
results = await searchCatalogAnime(title);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`[Miruro] Catalog search "${title}" failed: ${error.message}`);
|
|
||||||
|
|
||||||
// A 403 means the catalog rejected the client itself (Cloudflare or
|
|
||||||
// an IP block); trying more title variants cannot help.
|
|
||||||
if (error.status === 403) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
continue;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const exact = results.find((anime) => getExternalIds(anime, 'anilist').includes(Number(targetId)));
|
const exact = results.find((anime) => getExternalIds(anime, 'anilist').includes(Number(targetId)));
|
||||||
@@ -355,10 +345,37 @@ async function findCatalogAnime(candidateIds, targetId, searchTitles) {
|
|||||||
return exact;
|
return exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
const candidate = results.find((anime) => matchesAnyAniListId(anime, candidateIds));
|
return results.find((anime) => matchesAnyAniListId(anime, candidateIds)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
if (candidate) {
|
async function findCatalogAnime(candidateIds, targetId, searchTitles) {
|
||||||
return candidate;
|
// The catalog excludes adult entries from a default search, so retry the
|
||||||
|
// same titles with is_adult=true when the normal pass found nothing.
|
||||||
|
for (const includeAdult of [false, true]) {
|
||||||
|
const titles = includeAdult ? searchTitles.slice(0, 3) : searchTitles;
|
||||||
|
|
||||||
|
for (const title of titles) {
|
||||||
|
let results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
results = await searchCatalogAnime(title, includeAdult);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`[Miruro] Catalog search "${title}" failed: ${error.message}`);
|
||||||
|
|
||||||
|
// A 403 means the catalog rejected the client itself (Cloudflare
|
||||||
|
// or an IP block); trying more title variants cannot help.
|
||||||
|
if (error.status === 403) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = pickCatalogMatch(results, candidateIds, targetId);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user