updates and new extensions

This commit is contained in:
2026-01-13 17:26:06 +01:00
parent 83c51a82da
commit e8d64174fd
15 changed files with 3516 additions and 468 deletions

View File

@@ -1,7 +1,7 @@
class AnimeAV1 {
constructor() {
this.type = "anime-board";
this.version = "1.3";
this.version = "1.4";
this.api = "https://animeav1.com";
}
@@ -12,25 +12,180 @@ class AnimeAV1 {
};
}
async search(query) {
getFilters() {
return {
letter: {
label: 'Letra',
type: 'select',
options: [
{ value: '', label: 'Seleccionar...' },
{ value: '#', label: '#' },
...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map(l => ({
value: l,
label: l
}))
]
},
category: {
label: 'Tipo',
type: 'multiselect',
options: [
{ value: 'tv-anime', label: 'TV Anime' },
{ value: 'pelicula', label: 'Película' },
{ value: 'ova', label: 'OVA' },
{ value: 'ona', label: 'ONA' },
{ value: 'especial', label: 'Especial' }
]
},
genre: {
label: 'Género',
type: 'multiselect',
options: [
{ value: 'accion', label: 'Acción' },
{ value: 'aventura', label: 'Aventura' },
{ value: 'ciencia-ficcion', label: 'Ciencia Ficción' },
{ value: 'comedia', label: 'Comedia' },
{ value: 'deportes', label: 'Deportes' },
{ value: 'drama', label: 'Drama' },
{ value: 'fantasia', label: 'Fantasía' },
{ value: 'misterio', label: 'Misterio' },
{ value: 'recuentos-de-la-vida', label: 'Recuentos de la Vida' },
{ value: 'romance', label: 'Romance' },
{ value: 'seinen', label: 'Seinen' },
{ value: 'shoujo', label: 'Shoujo' },
{ value: 'shounen', label: 'Shounen' },
{ value: 'sobrenatural', label: 'Sobrenatural' },
{ value: 'suspenso', label: 'Suspenso' },
{ value: 'terror', label: 'Terror' },
{ value: 'artes-marciales', label: 'Artes Marciales' },
{ value: 'ecchi', label: 'Ecchi' },
{ value: 'escolares', label: 'Escolares' },
{ value: 'gore', label: 'Gore' },
{ value: 'harem', label: 'Harem' },
{ value: 'historico', label: 'Histórico' },
{ value: 'isekai', label: 'Isekai' },
{ value: 'josei', label: 'Josei' },
{ value: 'magia', label: 'Magia' },
{ value: 'mecha', label: 'Mecha' },
{ value: 'militar', label: 'Militar' },
{ value: 'mitologia', label: 'Mitología' },
{ value: 'musica', label: 'Música' },
{ value: 'parodia', label: 'Parodia' },
{ value: 'psicologico', label: 'Psicológico' },
{ value: 'superpoderes', label: 'Superpoderes' },
{ value: 'vampiros', label: 'Vampiros' },
{ value: 'yuri', label: 'Yuri' },
{ value: 'yaoi', label: 'Yaoi' }
]
},
year: {
label: 'Año (Máximo)',
type: 'number'
},
status: {
label: 'Estado',
type: 'select',
options: [
{ value: 'emision', label: 'En emisión' },
{ value: 'finalizado', label: 'Finalizado' },
{ value: 'proximamente', label: 'Próximamente' }
]
},
order: {
label: 'Ordenar por',
type: 'select',
options: [
{ value: 'default', label: 'Por defecto' },
{ value: 'updated', label: 'Recientes' },
{ value: 'likes', label: 'Populares' },
{ value: 'title', label: 'Alfabético' }
]
}
};
}
async search({ query, filters }) {
if (query && (!filters || Object.keys(filters).length === 0)) {
const res = await fetch(`${this.api}/api/search`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: query.query }),
body: JSON.stringify({ query }),
});
if (!res.ok) return [];
const data = await res.json();
return data.map((anime) => ({
return data.map(anime => ({
id: anime.slug,
title: anime.title,
url: `${this.api}/media/${anime.slug}`,
subOrDub: "both",
image: `https://cdn.animeav1.com/covers/${anime.id}.jpg`,
}));
}
const params = new URLSearchParams();
if (filters) {
if (filters.category) {
const cats = String(filters.category).split(',');
cats.forEach(c => {
if(c.trim()) params.append('category', c.trim());
});
}
if (filters.genre) {
const genres = String(filters.genre).split(',');
genres.forEach(g => {
if(g.trim()) params.append('genre', g.trim());
});
}
if (filters.year) params.set('maxYear', String(filters.year));
if (filters.status) params.set('status', filters.status);
if (filters.letter) params.set('letter', filters.letter);
if (filters.order && filters.order !== 'default') params.set('order', filters.order);
}
const url = `${this.api}/catalogo?${params.toString()}`;
const res = await fetch(url);
if (!res.ok) return [];
const html = await res.text();
const $ = this.cheerio.load(html);
const results = [];
$('article.group\\/item').each((_, el) => {
const card = $(el);
const title = card.find('h3').first().text().trim();
const href = card.find('a[href^="/media/"]').attr('href');
const img = card.find('img').first().attr('src');
if (!href) return;
const slug = href.replace('/media/', '');
results.push({
id: slug,
title,
url: `${this.api}${href}`,
image: img || '',
year: null
});
});
return results;
}
async getMetadata(id) {
const html = await fetch(`${this.api}/media/${id}`).then((r) => r.text());
const parsed = this.parseSvelteData(html);
@@ -74,18 +229,10 @@ class AnimeAV1 {
}
async findEpisodeServer(episodeOrId, _server, category = "sub") {
const ep =
typeof episodeOrId === "string"
? (() => {
try {
return JSON.parse(episodeOrId);
} catch {
return { id: episodeOrId };
}
})()
const ep = typeof episodeOrId === "string"
? JSON.parse(episodeOrId)
: episodeOrId;
let pageUrl = ep.url;
if (!pageUrl && typeof ep.id === "string") {
@@ -97,36 +244,22 @@ class AnimeAV1 {
}
}
if (!pageUrl) {
throw new Error(
`No se pudo determinar la URL del episodio (id=${ep.id}, number=${ep.number})`
);
}
if (!pageUrl) throw new Error("No se pudo determinar la URL del episodio.");
const html = await fetch(pageUrl).then((r) => r.text());
const parsedData = this.parseSvelteData(html);
const entry = parsedData.find((x) => x?.data?.embeds);
const embeds = entry?.data?.embeds;
if (!embeds) throw new Error("No embeds encontrados");
const list =
category === "dub"
? embeds.DUB
: embeds.SUB;
const list = category === "dub" ? embeds.DUB : embeds.SUB;
if (!Array.isArray(list))
throw new Error(`No hay streams ${category.toUpperCase()}`);
if (!Array.isArray(list)) throw new Error(`No hay streams ${category.toUpperCase()}`);
const hls = list.find(
(m) =>
m.server === "HLS" &&
m.url?.includes("zilla-networks.com/play/")
);
const hls = list.find(m => m.server === "HLS" && m.url?.includes("zilla-networks.com/play/"));
if (!hls)
throw new Error(`No se encontró stream HLS ${category.toUpperCase()}`);
if (!hls) throw new Error(`No se encontró stream HLS ${category.toUpperCase()}`);
return {
server: "HLS",

View File

@@ -3,7 +3,7 @@ class OppaiStream {
this.baseUrl = "https://oppai.stream";
this.searchBaseUrl = "https://oppai.stream/actions/search.php?order=recent&page=1&limit=35&genres=&blacklist=&studio=&ibt=0&swa=1&text=";
this.type = "anime-board";
this.version = "1.0";
this.version = "1.2";
this.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36";
this.ScoreWeight = {
@@ -19,48 +19,178 @@ class OppaiStream {
};
}
async search(queryObj) {
let tempquery = queryObj.query;
getGenreOptions() {
return [
'4k','ahegao','anal','armpitmasturbation','bdsm','beach','bigboobs',
'blackhair','blondehair','blowjob','bluehair','bondage','boobjob',
'brownhair','censored','comedy','cosplay','cowgirl','creampie',
'darkskin','demon','doggy','dominantgirl','doublepenetration','elf',
'facial','fantasy','filmed','footjob','futanari','gangbang',
'girlsonly','glasses','greenhair','gyaru','hd','handjob','harem',
'horror','incest','inflation','invertednipples','lactation','loli',
'maid','masturbation','milf','mindbreak','mindcontrol','missionary',
'monster','ntr','nekomimi','nurse','old','orgy','pov','pinkhair',
'plot','pregnant','publicsex','purplehair','rape','redhair',
'reversegangbang','reverserape','rimjob','scat','schoolgirl',
'shorthair','shota','smallboobs','softcore','succubus','swimsuit',
'teacher','tentacle','threesome','toys','trap','tripplepenetration',
'tsundere','uglybastard','uncensored','vampire','vanilla','virgin',
'watersports','whitehair','x-ray','yaoi','yuri'
].map(g => ({ value: g, label: g }));
}
getStudioOptions() {
return [
"44℃ Baidoku","AT-X","AXsiZ","Alice Soft","Antechinus","An♥Tekinus",
"BOOTLEG","BREAKBOTTLE","Bomb! Cute! Bomb!","Breakbottle","Bunny Walker",
"ChuChu","Collaboration Works","Cotton Doll","Digital Works",
"Global Solutions","HiLLS","Himajin Planning","JapanAnime","Jumondou",
"Kitty Media","Lune Pictures","MS Pictures","Magic Bus","Magin Label",
"Majin Petit","Majin petit","Majin","Mary Jane","Mediabank",
"Milky Animation Label","Mirai Koujou",
"NBCUniversal Entertainment Japan","Natural High","NewGeneration",
"Nippon Columbia","Nur","Office Nobu","Pashima","Pashmina","Passione",
"Peak Hunt","Pink Pineapple","PoRO petit","PoRO","Queen Bee",
"Rabbit Gate","Seven","Shion","Show-Ten","Shueisha","Studio 1st",
"Studio Gokumi","Studio Houkiboshi","Suzuki Mirano","T-Rex",
"TEATRO Nishi Tokyo Studio","TNK","Toranoana","WHITE BEAR","Y.O.U.C",
"YTV","Yomiuri TV Enterprise","ZIZ Entertainment","erozuki"
].map(s => ({ value: s, label: s }));
}
getFilters() {
return {
order: {
label: 'Sort By',
type: 'select',
options: [
{ value: 'az', label: 'A-Z' },
{ value: 'za', label: 'Z-A' },
{ value: 'recent', label: 'Recently Released' },
{ value: 'old', label: 'Oldest Releases' },
{ value: 'views', label: 'Most Views' },
{ value: 'rating', label: 'Highest Rated' },
{ value: 'uploaded', label: 'Recently Uploaded' },
{ value: 'random', label: 'Randomize' },
]
},
// TRI-STATE SIMULADO CON MULTISELECT
genre_include: {
label: 'Genre (Include)',
type: 'multiselect',
options: this.getGenreOptions()
},
genre_exclude: {
label: 'Genre (Exclude)',
type: 'multiselect',
options: this.getGenreOptions()
},
studio: {
label: 'Studio',
type: 'multiselect',
options: this.getStudioOptions()
}
};
}
async search({ query = "", filters }) {
let tempquery = query || "";
// 👉 si no hay texto pero sí filtros, hacemos una sola búsqueda
const hasFilters = filters && Object.keys(filters).length > 0;
let firstRun = true;
while (firstRun || tempquery !== "") {
firstRun = false;
while (tempquery !== "") {
try {
const url = this.searchBaseUrl + encodeURIComponent(tempquery);
const params = new URLSearchParams();
// SOLO ponemos text si existe
if (tempquery) params.set("text", tempquery);
if (filters) {
if (filters.order) params.set("order", filters.order);
if (filters.genre_include) {
const inc = String(filters.genre_include).split(',').map(x => x.trim()).filter(Boolean);
if (inc.length) params.set("genres", inc.join(','));
}
if (filters.genre_exclude) {
const exc = String(filters.genre_exclude).split(',').map(x => x.trim()).filter(Boolean);
if (exc.length) params.set("blacklist", exc.join(','));
}
if (filters.studio) {
const studios = String(filters.studio).split(',').map(x => x.trim()).filter(Boolean);
if (studios.length) params.set("studio", studios.join(','));
}
}
params.set("page", "1");
params.set("limit", "35");
const url = `${this.baseUrl}/actions/search.php?${params.toString()}`;
const html = await this.GETText(url);
const $ = this.cheerio.load(html);
const movies = $("div.in-grid.episode-shown");
// 👉 si no hay resultados:
if (movies.length <= 0) {
// si hay filtros, no hacemos fallback por palabras
if (hasFilters || !tempquery) return [];
// fallback normal cuando hay texto
if (tempquery.includes(" ")) {
tempquery = tempquery.split(/[\s:']+/).slice(0, -1).join(" ");
continue;
} else {
break;
}
return [];
}
const movieList = [];
const results = [];
movies.each((_, el) => {
const title = $(el).find(".title-ep").text().trim();
const href = $(el).find("a").attr("href");
const elObj = $(el);
const title = elObj.find(".title-ep .title").text().trim();
const href = elObj.find("a").attr("href");
const rawUrl = href ? href.replace("&for=search", "") : "";
const image = elObj.find(".cover-img-in").attr("src")
|| elObj.find(".cover-img-in").attr("original");
if (title && rawUrl) {
movieList.push({ Title: title, Url: rawUrl });
results.push({
id: encodeURIComponent(rawUrl),
title,
url: rawUrl,
image,
subOrDub: "sub",
});
}
});
const bestMovie = this.findBestTitle(movieList, queryObj.query);
if (!bestMovie) return [];
// 👉 si hay query usamos tu sistema de score
if (query) {
const best = this.findBestTitle(
results.map(r => ({ Title: r.title, Url: r.url, Image: r.image })),
query
);
if (!best) return [];
return [{
// Codificamos la URL para que sea un ID seguro para la URL de la app
id: encodeURIComponent(bestMovie.Url),
title: bestMovie.Title,
url: bestMovie.Url,
subOrDub: queryObj.dub ? "dub" : "sub",
id: encodeURIComponent(best.Url),
title: best.Title,
url: best.Url,
image: best.Image,
subOrDub: "sub",
}];
}
// 👉 si NO hay query, devolvemos todo (modo catálogo)
return results;
} catch (e) {
console.error(e);
@@ -74,6 +204,7 @@ class OppaiStream {
try {
// Decodificamos el ID para obtener la URL real de OppaiStream
const decodedUrl = decodeURIComponent(id);
console.log(decodedUrl)
const html = await this.GETText(decodedUrl);
const $ = this.cheerio.load(html);

437
anime/hentaila.js Normal file
View File

@@ -0,0 +1,437 @@
class Hentaila {
constructor() {
this.baseUrl = "https://hentaila.com";
this.cdnUrl = "https://cdn.hentaila.com";
this.type = "anime-board";
this.version = "1.0";
}
getFilters() {
return {
sort: {
label: "Ordenar por",
type: "select",
options: [
{ value: "latest_released", label: "Recientes" },
{ value: "popular", label: "Populares" }
],
default: "latest_released"
},
genres: {
label: "Géneros",
type: "select",
options: [
{ value: "3d", label: "3D" },
{ value: "ahegao", label: "Ahegao" },
{ value: "anal", label: "Anal" },
{ value: "casadas", label: "Casadas" },
{ value: "chikan", label: "Chikan" },
{ value: "ecchi", label: "Ecchi" },
{ value: "enfermeras", label: "Enfermeras" },
{ value: "futanari", label: "Futanari" },
{ value: "escolares", label: "Escolares" },
{ value: "gore", label: "Gore" },
{ value: "hardcore", label: "Hardcore" },
{ value: "harem", label: "Harem" },
{ value: "incesto", label: "Incesto" },
{ value: "juegos-sexuales", label: "Juegos Sexuales" },
{ value: "milfs", label: "Milfs" },
{ value: "maids", label: "Maids" },
{ value: "netorare", label: "Netorare" },
{ value: "ninfomania", label: "Ninfomanía" },
{ value: "ninjas", label: "Ninjas" },
{ value: "orgias", label: "Orgías" },
{ value: "romance", label: "Romance" },
{ value: "shota", label: "Shota" },
{ value: "softcore", label: "Softcore" },
{ value: "succubus", label: "Succubus" },
{ value: "teacher", label: "Teacher" },
{ value: "tentaculos", label: "Tentáculos" },
{ value: "tetonas", label: "Tetonas" },
{ value: "vanilla", label: "Vanilla" },
{ value: "violacion", label: "Violación" },
{ value: "virgenes", label: "Vírgenes" },
{ value: "yaoi", label: "Yaoi" },
{ value: "yuri", label: "Yuri" },
{ value: "bondage", label: "Bondage" },
{ value: "elfas", label: "Elfas" },
{ value: "petit", label: "Petit" },
{ value: "threesome", label: "Threesome" },
{ value: "paizuri", label: "Paizuri" },
{ value: "gal", label: "Gal" },
{ value: "oyakodon", label: "Oyakodon" }
]
},
status: {
label: "Estado",
type: "select",
options: [
{ value: "emision", label: "En Emisión" },
{ value: "finalizado", label: "Finalizado" }
]
},
uncensored: {
label: "Sin Censura",
type: "checkbox",
default: false
}
};
}
getSettings() {
return {
episodeServers: ["StreamWish", "VidHide"], //"VIP" works but the stream is blocked even with the headers.
supportsDub: false
};
}
_resolveRemixData(json) {
if (!json || !json.nodes) return [];
for (const node of json.nodes) {
if (node && node.uses && node.uses.search_params) {
const data = node.data;
if (!data || data.length === 0) continue;
const rootConfig = data[0];
if (!rootConfig || typeof rootConfig.results !== 'number') continue;
const resultsIndex = rootConfig.results;
const animePointers = data[resultsIndex];
if (!Array.isArray(animePointers)) continue;
return animePointers.map(pointer => {
const rawObj = data[pointer];
if (!rawObj) return null;
const realId = data[rawObj.id];
const title = data[rawObj.title];
const slug = data[rawObj.slug];
// Validación básica
if (!title || !slug) return null;
return {
id: slug,
title: title,
url: `${this.baseUrl}/media/${slug}`,
image: `${this.cdnUrl}/covers/${realId}.jpg`,
year: null
};
}).filter(Boolean);
}
}
return [];
}
async search(queryObj) {
const { query, filters, page } = queryObj;
const pageNum = page || 1;
let url = `${this.baseUrl}/catalogo/__data.json?page=${pageNum}`;
if (query && query.trim() !== "") {
url += `&search=${encodeURIComponent(query)}`;
} else {
if (filters.sort) url += `&order=${filters.sort}`;
else url += `&order=latest_released`;
if (filters.genres) url += `&genre=${filters.genres}`;
if (filters.status) url += `&status=${filters.status}`;
if (filters.uncensored) url += `&uncensored=`;
}
try {
const response = await fetch(url);
const json = await response.json();
return this._resolveRemixData(json);
} catch (error) {
console.error("Error searching Hentaila:", error);
return [];
}
}
async getMetadata(id) {
const url = `${this.baseUrl}/media/${id}`;
try {
const response = await fetch(url);
const html = await response.text();
const $ = this.cheerio.load(html);
const title = $(".grid.items-start h1.text-lead").first().text().trim();
const image = $("img.object-cover.w-full.aspect-poster").first().attr("src");
const summary = $(".entry.text-lead.text-sm p").text().trim();
// Estado
const statusText = $("div.flex.flex-wrap.items-center.text-sm span").text();
const status = statusText.includes("En emisión") ? "En Emisión" : "Finalizado";
// Géneros
const genres = [];
$(".flex-wrap.items-center .btn.btn-xs.rounded-full").each((i, el) => {
const txt = $(el).text().trim();
if (txt) genres.push(txt);
});
const episodeCount = $("article.group\\/item").length;
return {
title: title,
summary: summary,
status: status,
genres: genres,
image: image,
episodes: episodeCount,
url: url
};
} catch (error) {
console.error("Error getting metadata:", error);
return null;
}
}
async findEpisodes(id) {
const url = `${this.baseUrl}/media/${id}`;
try {
const response = await fetch(url);
const html = await response.text();
const $ = this.cheerio.load(html);
const episodes = [];
$("article.group\\/item").each((i, el) => {
const $el = $(el);
const numberText = $el.find("span.text-lead").text().trim();
const number = parseFloat(numberText);
const relativeUrl = $el.find("a").attr("href");
const image = $el.find("img").attr("src");
if (!isNaN(number) && relativeUrl) {
episodes.push({
id: JSON.stringify({ slug: id, number: number }),
number: number,
title: `Episodio ${number}`,
url: `${this.baseUrl}${relativeUrl}`,
image: image
});
}
});
return episodes;
} catch (error) {
console.error("Error finding episodes:", error);
return [];
}
}
async findEpisodeServer(episodeOrId, _server, category = "sub") {
let slug, number;
const ep = typeof episodeOrId === "string"
? JSON.parse(episodeOrId)
: episodeOrId;
if (ep.id && typeof ep.id === "string" && ep.id.startsWith("{")) {
const p = JSON.parse(ep.id);
slug = p.slug;
number = p.number;
} else {
slug = ep.slug;
number = ep.number;
}
if (!slug || !number) throw new Error("No se pudo determinar episodio");
const url = `${this.baseUrl}/media/${slug}/${number}/__data.json`;
const json = await fetch(url).then(r => r.json());
let chosen = null;
const wanted = (_server || "VIP").toLowerCase();
if (json.nodes) {
for (const node of json.nodes) {
if (!node?.uses?.params?.includes("number")) continue;
const data = node.data;
const root = data?.[0];
if (!root || typeof root.embeds !== "number") continue;
const embeds = data[root.embeds];
const listIndex = category === "dub" ? embeds?.DUB : embeds?.SUB;
if (typeof listIndex !== "number") continue;
const list = data[listIndex];
if (!Array.isArray(list)) continue;
for (const i of list) {
const v = data[i];
const server = data[v.server];
const link = data[v.url];
if (!server || !link) continue;
if (server.toLowerCase() !== wanted) continue;
let finalUrl = link;
let type = "iframe";
// --- VIP → m3u8 directo ---
const serverName = server.toLowerCase();
// --- VIP ---
if (serverName === "vip") {
finalUrl = link.replace("/play/", "/m3u8/");
type = "m3u8";
}
// --- STREAMWISH ---
else if (serverName === "streamwish") {
const m3u8 = await this.extractPackedM3U8(link);
if (m3u8) {
finalUrl = m3u8;
type = "m3u8";
}
}
else if (serverName === "vidhide") {
const m3u8 = await this.extractPackedM3U8(link);
if (m3u8) {
finalUrl = m3u8;
type = "m3u8";
}
}
chosen = {
url: finalUrl,
type,
quality: server,
subtitles: [],
subOrDub: category
};
break;
}
}
}
if (!chosen) throw new Error(`No se encontró el server ${_server}`);
return {
server: _server || "VIP",
headers: {
Referer: "https://hentaila.com/",
Origin: "https://hentaila.com"
},
videoSources: [chosen]
};
}
async extractPackedM3U8(embedUrl) {
try {
const { result } = await this.scrape(embedUrl, async (page) => {
try {
await page.waitForSelector('script', { state: 'attached', timeout: 5000 });
} catch (e) {}
return await page.evaluate(() => {
function unpack(code) {
try {
const regex = /}\s*\('(.*?)',\s*(\d+),\s*(\d+),\s*'(.*?)'\.split\('\|'\)/;
const m = code.match(regex);
if (!m) return null;
let payload = m[1].replace(/\\'/g, "'");
const radix = parseInt(m[2]);
const count = parseInt(m[3]);
const dict = m[4].split('|');
const unbase = (val) => {
const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (radix > 62) return parseInt(val, radix);
const alphabet = chars.slice(0, radix);
let ret = 0;
const reversed = val.split('').reverse().join('');
for (let i = 0; i < reversed.length; i++) {
const index = alphabet.indexOf(reversed[i]);
if (index === -1) continue;
ret += index * Math.pow(radix, i);
}
return ret;
};
return payload.replace(/\b\w+\b/g, (word) => {
const index = unbase(word);
if (dict[index]) return dict[index];
return word;
});
} catch (e) {
return "ERROR_IN_UNPACKER: " + e.message;
}
}
// --- BÚSQUEDA DEL SCRIPT ---
const scripts = Array.from(document.getElementsByTagName('script'));
for (const script of scripts) {
const content = script.textContent;
if (!content) continue;
// Buscamos la firma del packer
if (content.includes('eval(function(p,a,c,k,e,d)') || content.includes('eval(function(p,a,c')) {
// Intentamos desempaquetar
const unpacked = unpack(content);
// Si funcionó y parece contener HTML/JS válido
if (unpacked && unpacked.length > 20 && !unpacked.startsWith("ERROR")) {
return unpacked;
}
}
}
return "NO_PACKER_FOUND";
});
}, {
waitUntil: "domcontentloaded",
renderWaitTime: 2000
});
if (!result || result === "NO_PACKER_FOUND") {
return null;
}
if (result.startsWith("ERROR")) {
return null;
}
const m3u8Regex = /(https?:\/\/[^"']+\.m3u8[^"']*)/;
const match = result.match(m3u8Regex);
if (match) {
return match[1];
} else {
console.log("[DEBUG] ⚠️ Script desempaquetado pero SIN m3u8. Dump parcial:", result.substring(0, 100));
}
return null;
} catch (error) {
return null;
}
}
}
module.exports = Hentaila;

266
anime/missav.js Normal file
View File

@@ -0,0 +1,266 @@
class MissAV {
constructor() {
this.type = "anime-board";
this.version = "1.0";
this.baseUrl = "https://missav.live";
}
getSettings() {
return {
supportsDub: false,
episodeServers: ["Default"],
};
}
/* ================= FILTERS ================= */
getFilters() {
return [
{
key: "sort",
name: "Sort by",
type: "select",
options: [
{ value: "", label: "Any" },
{ value: "released_at", label: "Release date" },
{ value: "published_at", label: "Recent update" },
{ value: "today_views", label: "Today views" },
{ value: "weekly_views", label: "Weekly views" },
{ value: "monthly_views", label: "Monthly views" },
{ value: "views", label: "Total views" },
],
},
{
key: "genre",
name: "Genres",
type: "select",
options: [
{ value: "", label: "<Select>" },
{ value: "en/uncensored-leak", label: "Uncensored Leak" },
{ value: "en/genres/Hd", label: "Hd" },
{ value: "en/genres/Exclusive", label: "Exclusive" },
{ value: "en/genres/Creampie", label: "Creampie" },
{ value: "en/genres/Big%20Breasts", label: "Big Breasts" },
{ value: "en/genres/Individual", label: "Individual" },
{ value: "en/genres/Wife", label: "Wife" },
{ value: "en/genres/Mature%20Woman", label: "Mature Woman" },
{ value: "en/genres/Pretty%20Girl", label: "Pretty Girl" },
{ value: "en/genres/Orgy", label: "Orgy" },
{ value: "en/genres/Lesbian", label: "Lesbian" },
{ value: "en/genres/Ntr", label: "NTR" },
{ value: "en/genres/Cosplay", label: "Cosplay" },
{ value: "en/genres/Uniform", label: "Uniform" },
{ value: "en/genres/Swimsuit", label: "Swimsuit" },
{ value: "en/genres/4K", label: "4K" },
{ value: "en/genres/Vr", label: "VR" },
],
},
{
type: "note",
text: "Genre filters ignored with text search!",
},
];
}
/* ================= SEARCH ================= */
async search(query) {
const filters = query?.filters || {};
const hasText = !!(query?.query && query.query.trim());
let url;
if (hasText) {
url = `${this.baseUrl}/en/search/${encodeURIComponent(query.query)}`;
} else if (filters.genre) {
url = `${this.baseUrl}/${filters.genre}`;
} else {
const params = new URLSearchParams();
if (filters.sort) params.set("sort", filters.sort);
url = `${this.baseUrl}/en?${params.toString()}`;
}
const { result, requests } = await this.scrape(
url,
async (page) => {
const html = await page.content();
const items = await page.$$eval(
'div.thumbnail',
nodes => nodes.map(n => {
const a = n.querySelector('a[href^="https://missav.live/en/"]');
if (!a) return null;
const href = a.getAttribute("href");
const img =
n.querySelector('img')?.getAttribute("data-src") ||
n.querySelector('img')?.getAttribute("src");
const title =
n.querySelector('div.text-sm a')?.textContent?.trim() ||
n.querySelector('a')?.textContent?.trim();
if (!href || !img || !title) return null;
return {
id: href.replace("https://missav.live", ""),
title,
image: img,
url: href,
};
}).filter(Boolean)
);
return items;
},
{
waitUntil: "domcontentloaded",
renderWaitTime: 1500,
scrollToBottom: true,
}
);
return result;
}
/* ================= METADATA ================= */
async getMetadata(animeId) {
const url = animeId.startsWith("http")
? animeId
: this.baseUrl + animeId;
console.log("[MissAV][meta] url =", url);
const { result, requests } = await this.scrape(
url,
async (page) => {
console.log("[MissAV][meta] page loaded");
const htmlSize = await page.content().then(h => h.length);
console.log("[MissAV][meta] html size =", htmlSize);
return await page.evaluate(() => {
const dbg = {};
const h1 = document.querySelector("h1");
dbg.hasH1 = !!h1;
const video = document.querySelector("video.player");
dbg.hasVideo = !!video;
const og = document.querySelector('meta[property="og:image"]');
dbg.hasOg = !!og;
const genreLinks = document.querySelectorAll('a[href^="/en/genres/"]');
dbg.genreCount = genreLinks.length;
const title =
document.querySelector("h1.text-base")?.textContent?.trim() ||
document.querySelector("h1")?.textContent?.trim() ||
"Unknown";
const poster =
video?.getAttribute("data-poster") ||
og?.content ||
null;
const description = "";
const genres = Array.from(genreLinks).map(a =>
a.textContent.trim()
);
return {
dbg,
title,
poster,
description,
genres,
};
});
},
{
waitUntil: "domcontentloaded",
timeout: 20000,
}
);
return {
title: result.title,
image: result.poster,
description: result.description,
genres: result.genres,
};
}
/* ================= EPISODES ================= */
async findEpisodes(animeId) {
// MissAV es 1 video = 1 episodio
return [
{
id: animeId,
number: 1,
title: "Video",
url: animeId.startsWith("http")
? animeId
: this.baseUrl + animeId,
},
];
}
/* ================= SERVERS ================= */
async findEpisodeServer(episode) {
const url = episode.url.startsWith("http")
? episode.url
: this.baseUrl + episode.url;
const { requests } = await this.scrape(
url,
async () => true,
{
waitUntil: "domcontentloaded",
timeout: 20000,
renderWaitTime: 1500,
}
);
const m3u8s = requests
.map(r => r.url)
.filter(u => u.includes(".m3u8"));
if (!m3u8s.length) throw new Error("No m3u8 in network");
// regla:
// - si existe .../playlist.m3u8 -> master
// - si no -> usar video.m3u8 (o el único que haya)
let finalUrl =
m3u8s.find(u => /\/playlist\.m3u8(\?|$)/.test(u)) ||
m3u8s.find(u => /\/video\.m3u8(\?|$)/.test(u)) ||
m3u8s[0];
return {
server: "Default",
videoSources: [
{
url: finalUrl,
type: "m3u8",
quality: "auto",
},
],
};
}
/* ================= UTILS ================= */
safeString(str) {
return typeof str === "string" ? str : "";
}
}
module.exports = MissAV;

290
anime/rouvideo.js Normal file
View File

@@ -0,0 +1,290 @@
class RouVideo {
constructor() {
this.baseUrl = "https://rou.video";
this.apiUrl = "https://rou.video/api";
this.type = "anime-board";
this.version = "1.0";
}
getFilters() {
return {
sort: {
label: "Ordenar por",
type: "select",
options: [
{ value: "createdAt", label: "Recent" },
{ value: "viewCount", label: "Most viewed" },
{ value: "likeCount", label: "Most liked" }
],
default: "createdAt"
},
category: {
label: "Categoría",
type: "select",
options: [
{ value: "all", label: "Todos los videos" },
{ value: "featured", label: "Destacados" },
{ value: "watching", label: "Viendo ahora" },
{ value: "國產AV", label: "Chinese AV" },
{ value: "中文字幕", label: "Chinese Sub" },
{ value: "麻豆傳媒", label: "Madou Media" },
{ value: "自拍流出", label: "Selfie Leaked" },
{ value: "探花", label: "Tanhua" },
{ value: "OnlyFans", label: "OnlyFans" },
{ value: "日本", label: "JAV" }
],
default: "all"
}
};
}
getSettings() {
return {
episodeServers: ["RouVideo"],
supportsDub: false,
};
}
async search(queryObj) {
const { query, filters, page } = queryObj;
const pageNum = page || 1;
const sort = filters?.sort || "createdAt";
const category = filters?.category || "all";
let url;
if (query && query.trim().length > 0) {
url = `${this.baseUrl}/search?q=${encodeURIComponent(query.trim())}&page=${pageNum}`;
if (category !== "all" && category !== "featured" && category !== "watching") {
url += `&t=${encodeURIComponent(category)}`;
}
} else {
if (category === "watching") {
url = `${this.apiUrl}/v/watching`;
} else if (category === "featured") {
url = `${this.baseUrl}/home`;
} else if (category !== "all") {
url = `${this.baseUrl}/t/${encodeURIComponent(category)}?page=${pageNum}&order=${sort}`;
} else {
url = `${this.baseUrl}/v?page=${pageNum}&order=${sort}`;
}
}
try {
if (category === "watching" && !query) {
const response = await this.requestApi(url);
const json = JSON.parse(response);
return json.map(this.parseVideoItem);
}
const response = await this.request(url);
const $ = this.cheerio.load(response);
const nextData = this.extractNextData($);
if (!nextData || !nextData.props || !nextData.props.pageProps) {
return [];
}
const props = nextData.props.pageProps;
let videos = [];
if (props.videos) {
videos = props.videos;
} else if (props.hotSearches && query) {
videos = props.videos || [];
} else if (category === "featured" || url.includes("/home")) {
videos = [
...(props.latestVideos || []),
...(props.hotCNAV || []),
...(props.hot91 || []),
...(props.hotSelfie || [])
];
}
return videos.map(this.parseVideoItem);
} catch (error) {
console.error("Error en search:", error);
return [];
}
}
async getMetadata(id) {
try {
const url = `${this.baseUrl}/v/${id}`;
const response = await this.request(url);
const $ = this.cheerio.load(response);
const nextData = this.extractNextData($);
if (!nextData) return { id, title: "Unknown" };
const video = nextData.props.pageProps.video;
if (!video) return { id, title: "Unknown" };
let descText = "";
if (video.sources && video.sources.length > 0) {
descText += `Resolution: ${video.sources[0].resolution}p\n`;
}
descText += `Duration: ${this.formatDuration(video.duration)}\n`;
descText += `View: ${video.viewCount}`;
if (video.likeCount) descText += ` - Like: ${video.likeCount}`;
if (video.ref) descText += `\nRef: ${video.ref}`;
if (video.description) descText += `\n\n${video.description}`;
return {
id: video.id,
title: video.name,
cover: video.coverImageUrl,
description: descText,
genres: video.tags || [],
author: video.tags?.[0] || "",
status: "Completed",
url: url
};
} catch (error) {
console.error("Error en getMetadata:", error);
return {};
}
}
async findEpisodes(id) {
try {
return [{
id: id,
number: 1,
title: "Movie"
}];
} catch (error) {
return [];
}
}
async findEpisodeServer(episodeInput, server, category = "sub") {
let cleanId = "";
if (typeof episodeInput === 'object' && episodeInput !== null) {
cleanId = episodeInput.id;
} else {
cleanId = episodeInput;
}
if (String(cleanId).includes('/')) {
cleanId = String(cleanId).split('/').pop();
}
console.log(`[RouVideo] Buscando servidor para ID: ${cleanId}`);
const apiUrl = `${this.apiUrl}/v/${cleanId}`;
try {
const req = await fetch(apiUrl, {
method: 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Host': 'rou.video',
'Origin': 'https://rou.video',
'Referer': 'https://rou.video/'
}
});
if (!req.ok) {
console.error(`[RouVideo] Error HTTP: ${req.status}`);
return { videoSources: [] };
}
const text = await req.text();
if (text.trim().startsWith("<")) {
console.error("[RouVideo] Error: La API devolvió HTML");
return { videoSources: [] };
}
const json = JSON.parse(text);
if (json?.video?.videoUrl) {
console.log("[RouVideo] Video URL encontrado:", json.video.videoUrl);
// Headers necesarios para reproducir el stream
const streamHeaders = {
"Referer": "https://rou.video/",
"Origin": "https://rou.video",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
};
return {
headers: streamHeaders,
videoSources: [{
server: "RouVideo",
url: json.video.videoUrl,
type: "m3u8",
quality: "Auto",
headers: streamHeaders
}]
};
} else {
console.warn("[RouVideo] JSON válido pero sin videoUrl");
return { videoSources: [] };
}
} catch (error) {
console.error("[RouVideo] Error fatal:", error);
return { videoSources: [] };
}
}
extractNextData($) {
try {
const scriptContent = $('#__NEXT_DATA__').html();
if (scriptContent) {
return JSON.parse(scriptContent);
}
} catch (e) {
console.error("Error parsing __NEXT_DATA__", e);
}
return null;
}
parseVideoItem(video) {
return {
id: video.id,
title: video.name,
image: video.coverImageUrl,
};
}
formatDuration(seconds) {
if (!seconds) return "0:00";
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = Math.floor(seconds % 60);
const mStr = m < 10 && h > 0 ? `0${m}` : m;
const sStr = s < 10 ? `0${s}` : s;
return h > 0 ? `${h}:${mStr}:${sStr}` : `${mStr}:${sStr}`;
}
async request(url) {
const req = await fetch(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': `${this.baseUrl}/`,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8'
}
});
return await req.text();
}
async requestApi(url) {
const req = await fetch(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': `${this.baseUrl}/`,
'Origin': this.baseUrl,
'Accept': 'application/json, text/plain, */*'
}
});
return await req.text();
}
}
module.exports = RouVideo;

186
anime/xvideos.js Normal file
View File

@@ -0,0 +1,186 @@
class Xvideos {
constructor() {
this.baseUrl = "https://www.xvideos.com";
this.type = "anime-board";
this.version = "1.0";
}
getSettings() {
return {
episodeServers: ["Default"],
supportsDub: false,
};
}
_encodeId(href) {
if (!href) return "";
let id = href.startsWith("/") ? href.substring(1) : href;
return id.replace(/\//g, "___");
}
_decodeId(id) {
if (!id) return "";
return id.replace(/___/g, "/");
}
async search({ query, tag = "", page = 1 }) {
let url;
if (query && query.trim()) {
url = `${this.baseUrl}/?k=${encodeURIComponent(query)}&p=${page}`;
} else if (tag) {
url = `${this.baseUrl}/tags/${tag}/${page}`;
} else {
url = `${this.baseUrl}/new/${page}`;
}
try {
const res = await fetch(url);
const html = await res.text();
const $ = this.cheerio.load(html);
const items = $("div#main div#content div.mozaique.cust-nb-cols > div").toArray();
const results = items.map(el => {
const a = $(el).find("div.thumb-inside div.thumb a");
const img = $(el).find("div.thumb-inside div.thumb a img");
const href = a.attr("href");
if (!href) return null;
const safeId = this._encodeId(href);
const thumbnail = img.attr("data-src") || img.attr("src") || "";
return {
id: safeId,
title: $(el).find("div.thumb-under p.title").text().trim(),
url: this.baseUrl + href,
image: thumbnail,
subOrDub: "sub",
};
}).filter(i => i !== null);
return results;
} catch (e) {
console.error("[ERROR] Fallo en Search:", e);
return [];
}
}
async getMetadata(id) {
const realPath = this._decodeId(id);
const fetchUrl = `${this.baseUrl}/${realPath}`;
try {
const res = await fetch(fetchUrl);
if (res.status === 404) throw new Error("Video no encontrado (404)");
const html = await res.text();
const $ = this.cheerio.load(html);
const title = $("h2.page-title").text().trim();
const genres = $("div.video-metadata ul li a span").toArray().map(e => $(e).text());
let image = "";
image = $('meta[property="og:image"]').attr('content');
if (!image) {
const regex = /html5player\.setThumbUrl\(\s*['"]([^'"]+)['"]/;
const match = html.match(regex);
if (match) image = match[1];
}
return {
title: title || "Unknown Title",
summary: "",
episodes: 1,
characters: [],
season: "",
status: "Completed",
studio: "",
score: null,
year: null,
genres: genres,
image: image || "",
};
} catch (e) {
console.error("[ERROR] Fallo en getMetadata:", e);
throw e;
}
}
async findEpisodes(id) {
return [
{
id: "video_main",
number: 1,
title: "Video",
url: id,
},
];
}
async findEpisodeServer(episode, server, category = "sub") {
const realPath = this._decodeId(episode.url);
const videoUrl = `${this.baseUrl}/${realPath}`;
try {
const res = await fetch(videoUrl);
const html = await res.text();
const videoSources = [];
const extract = (key) => {
const regex = new RegExp(`${key}\\s*\\(\\s*['"]([^'"]+)['"]`);
const match = html.match(regex);
return match ? match[1] : null;
};
const low = extract("html5player.setVideoUrlLow");
const high = extract("html5player.setVideoUrlHigh");
const hls = extract("html5player.setVideoHLS");
if (hls) {
videoSources.push({
url: hls,
type: "m3u8",
quality: "Auto",
subOrDub: category
});
} else if (high) {
videoSources.push({
url: high,
type: "mp4",
quality: "High",
subOrDub: category
});
} else if (low) {
videoSources.push({
url: low,
type: "mp4",
quality: "Low",
subOrDub: category
});
}
if (videoSources.length === 0) throw new Error("No sources found");
return {
server: server || "Default",
headers: { Referer: this.baseUrl },
videoSources: videoSources,
};
} catch (e) {
console.error("[ERROR] Fallo en findEpisodeServer:", e);
throw e;
}
}
}
module.exports = Xvideos;

View File

@@ -2,13 +2,50 @@ class asmhentai {
constructor() {
this.baseUrl = "https://asmhentai.com";
this.type = "book-board";
this.version = "1.1"
this.version = "1.2";
this.mediaType = "manga";
}
async search(queryObj) {
const q = (queryObj.query || "").trim().replace(/\s+/g, "+");
const html = await fetch(`${this.baseUrl}/search/?q=${q}&page=1`).then(r => r.text());
getFilters() {
return {
sort: {
label: "Order",
type: "select",
options: [
{ value: "latest", label: "Latest" },
{ value: "popular", label: "Popular" }
],
default: "latest"
}
};
}
async search({ query, page = 1, filters }) {
let url;
if (query && query.trim().length > 0) {
const q = query.trim().replace(/\s+/g, "+");
url = `${this.baseUrl}/search/?q=${q}&page=${page}`;
}
else {
const sort = filters?.sort || "latest";
if (sort === "popular") {
url = page === 1
? `${this.baseUrl}/popular/`
: `${this.baseUrl}/popular/pag/${page}/`;
} else {
url = page === 1
? `${this.baseUrl}/`
: `${this.baseUrl}/pag/${page}/`;
}
}
const html = await fetch(url).then(r => r.text());
const $ = this.cheerio.load(html);
const results = [];
@@ -16,6 +53,7 @@ class asmhentai {
$(".preview_item").each((_, el) => {
const href = $(el).find(".image a").attr("href");
const id = href?.match(/\/g\/(\d+)\//)?.[1];
if (!id) return;
let img = $(el).find(".image img").attr("data-src") || $(el).find(".image img").attr("src") || "";
@@ -49,7 +87,7 @@ class asmhentai {
const genres = $(".tags a.tag")
.map((_, el) => $(el).text().trim())
.get()
.get();
return {
id,
@@ -111,14 +149,10 @@ class asmhentai {
return url;
})
.filter(url => {
// Mantenemos el filtro que te funcionó
return url && url.includes("images.") && !url.includes("/images/");
})
.map((url, i) => {
// Reemplazamos "thumb" por el número del índice + 1
// Ejemplo: .../thumb.jpg -> .../1.jpg
const newUrl = url.replace("thumb", (i + 1).toString());
return {
index: i,
url: newUrl

View File

@@ -3,7 +3,7 @@ class Comix {
this.baseUrl = "https://comix.to";
this.apiUrl = "https://comix.to/api/v2";
this.type = "book-board";
this.version = "1.0";
this.version = "1.1";
this.mediaType = "manga";
}
@@ -14,18 +14,212 @@ class Comix {
};
}
getFilters() {
const currentYear = new Date().getFullYear();
const years = [];
for (let i = currentYear; i >= 1990; i--) {
years.push({ value: i.toString(), label: i.toString() });
}
years.push({ value: "older", label: "Older" });
return {
sort: {
label: "Sort By",
type: "select",
options: [
{ value: "relevance", label: "Best Match" },
{ value: "views_30d", label: "Popular (30 days)" },
{ value: "views_total", label: "Total Views" },
{ value: "chapter_updated_at", label: "Latest Updates" },
{ value: "created_at", label: "Created Date" },
{ value: "title", label: "Title" },
{ value: "year", label: "Year" },
{ value: "follows_total", label: "Most Follows" }
],
default: "views_30d"
},
status: {
label: "Status",
type: "multiselect",
options: [
{ value: "finished", label: "Finished" },
{ value: "releasing", label: "Releasing" },
{ value: "on_hiatus", label: "On Hiatus" },
{ value: "discontinued", label: "Discontinued" },
{ value: "not_yet_released", label: "Not Yet Released" }
]
},
type: {
label: "Type",
type: "multiselect",
options: [
{ value: "manga", label: "Manga" },
{ value: "manhwa", label: "Manhwa" },
{ value: "manhua", label: "Manhua" },
{ value: "other", label: "Other" }
]
},
demographic: {
label: "Demographic",
type: "multiselect",
options: [
{ value: "1", label: "Shoujo" },
{ value: "2", label: "Shounen" },
{ value: "3", label: "Josei" },
{ value: "4", label: "Seinen" }
]
},
genre: {
label: "Genres",
type: "multiselect",
options: [
{ value: "6", label: "Action" },
{ value: "87264", label: "Adult" },
{ value: "7", label: "Adventure" },
{ value: "8", label: "Boys Love" },
{ value: "9", label: "Comedy" },
{ value: "10", label: "Crime" },
{ value: "11", label: "Drama" },
{ value: "87265", label: "Ecchi" },
{ value: "12", label: "Fantasy" },
{ value: "13", label: "Girls Love" },
{ value: "87266", label: "Hentai" },
{ value: "14", label: "Historical" },
{ value: "15", label: "Horror" },
{ value: "16", label: "Isekai" },
{ value: "17", label: "Magical Girls" },
{ value: "87267", label: "Mature" },
{ value: "18", label: "Mecha" },
{ value: "19", label: "Medical" },
{ value: "20", label: "Mystery" },
{ value: "21", label: "Philosophical" },
{ value: "22", label: "Psychological" },
{ value: "23", label: "Romance" },
{ value: "24", label: "Sci-Fi" },
{ value: "25", label: "Slice of Life" },
{ value: "87268", label: "Smut" },
{ value: "26", label: "Sports" },
{ value: "27", label: "Superhero" },
{ value: "28", label: "Thriller" },
{ value: "29", label: "Tragedy" },
{ value: "30", label: "Wuxia" },
{ value: "31", label: "Aliens" },
{ value: "32", label: "Animals" },
{ value: "33", label: "Cooking" },
{ value: "34", label: "Cross Dressing" },
{ value: "35", label: "Delinquents" },
{ value: "36", label: "Demons" },
{ value: "37", label: "Genderswap" },
{ value: "38", label: "Ghosts" },
{ value: "39", label: "Gyaru" },
{ value: "40", label: "Harem" },
{ value: "41", label: "Incest" },
{ value: "42", label: "Loli" },
{ value: "43", label: "Mafia" },
{ value: "44", label: "Magic" },
{ value: "45", label: "Martial Arts" },
{ value: "46", label: "Military" },
{ value: "47", label: "Monster Girls" },
{ value: "48", label: "Monsters" },
{ value: "49", label: "Music" },
{ value: "50", label: "Ninja" },
{ value: "51", label: "Office Workers" },
{ value: "52", label: "Police" },
{ value: "53", label: "Post-Apocalyptic" },
{ value: "54", label: "Reincarnation" },
{ value: "55", label: "Reverse Harem" },
{ value: "56", label: "Samurai" },
{ value: "57", label: "School Life" },
{ value: "58", label: "Shota" },
{ value: "59", label: "Supernatural" },
{ value: "60", label: "Survival" },
{ value: "61", label: "Time Travel" },
{ value: "62", label: "Traditional Games" },
{ value: "63", label: "Vampires" },
{ value: "64", label: "Video Games" },
{ value: "65", label: "Villainess" },
{ value: "66", label: "Virtual Reality" },
{ value: "67", label: "Zombies" }
]
},
year_from: {
label: "Year From",
type: "select",
options: [{ value: "", label: "Any" }, ...years]
},
year_to: {
label: "Year To",
type: "select",
options: [{ value: "", label: "Any" }, ...years]
},
min_chap: {
label: "Min. Chapters",
type: "number",
placeholder: "e.g. 10"
}
};
}
async search(queryObj) {
const q = (queryObj.query || "").trim().replace(/\s+/g, "+");
const { query, filters, page } = queryObj;
const q = (query || "").trim().replace(/\s+/g, "+");
const pageNum = page || 1;
const url = new URL(`${this.apiUrl}/manga`);
let sortMode = "views_30d";
if (filters) {
if (filters.sort) {
sortMode = filters.sort;
}
if (filters.genre) {
const genres = String(filters.genre).split(',');
genres.forEach(g => {
if (g.trim()) url.searchParams.append("genres[]", g.trim());
});
}
if (filters.status) {
const statuses = String(filters.status).split(',');
statuses.forEach(s => {
if (s.trim()) url.searchParams.append("statuses[]", s.trim());
});
}
if (filters.type) {
const types = String(filters.type).split(',');
types.forEach(t => {
if (t.trim()) url.searchParams.append("types[]", t.trim());
});
}
if (filters.demographic) {
const demos = String(filters.demographic).split(',');
demos.forEach(d => {
if (d.trim()) url.searchParams.append("demographics[]", d.trim());
});
}
if (filters.year_from) url.searchParams.set("release_year[from]", filters.year_from);
if (filters.year_to) url.searchParams.set("release_year[to]", filters.year_to);
if (filters.min_chap) url.searchParams.set("min_chap", filters.min_chap);
}
if (q) {
url.searchParams.set("keyword", q);
url.searchParams.set("order[relevance]", "desc");
} else {
url.searchParams.set("order[views_30d]", "desc");
sortMode = "relevance";
}
const orderDirection = (sortMode === "title") ? "asc" : "desc";
url.searchParams.set(`order[${sortMode}]`, orderDirection);
url.searchParams.set("limit", "50");
url.searchParams.set("page", "1");
url.searchParams.set("page", pageNum.toString());
const res = await fetch(url, { headers: this.headers });
if (!res.ok) throw new Error(`Search failed: ${res.status}`);
@@ -37,12 +231,15 @@ class Comix {
title: m.title,
image: m.poster?.large || null,
rating: m.score ?? null,
type: "book"
type: "book",
year: m.year || null,
status: m.status || null
}));
}
async getMetadata(id) {
const url = `${this.apiUrl}/manga/${id}?includes[]=genre&includes[]=author&includes[]=artist`;
const url = `${this.apiUrl}/manga/${id}?includes[]=genre&includes[]=author&includes[]=artist&includes[]=demographic`;
const res = await fetch(url, { headers: this.headers });
if (!res.ok) throw new Error(`Metadata failed: ${res.status}`);
@@ -99,12 +296,13 @@ class Comix {
if (ch.language !== "en") continue;
const key = ch.number;
if (!map.has(key) || ch.is_official === 1) {
map.set(key, ch);
}
}
return Array.from(map.values())
const chapters = Array.from(map.values())
.sort((a, b) => a.number - b.number)
.map((ch, i) => ({
id: `${mangaId}|${slug}|${ch.chapter_id}|${ch.number}`,
@@ -115,33 +313,27 @@ class Comix {
releaseDate: ch.updated_at ?? null,
index: i
}));
return chapters;
}
async findChapterPages(chapterId) {
const parts = chapterId.split("|");
console.log(parts)
if (parts.length < 4) return [];
const [hashId, slug, chapterRealId, number] = parts;
const readerUrl = `${this.baseUrl}/title/${hashId}-${slug}/${chapterRealId}-chapter-${number}`;
const res = await fetch(readerUrl, { headers: this.headers });
const apiUrl = `${this.apiUrl}/chapters/${chapterRealId}`;
const res = await fetch(apiUrl, { headers: this.headers });
if (!res.ok) return [];
const html = await res.text();
const json = await res.json();
if (!json.result || !json.result.images) return [];
const regex = /["\\]*images["\\]*\s*:\s*(\[[^\]]*\])/s;
const match = html.match(regex);
if (!match?.[1]) return [];
let images;
try {
images = JSON.parse(match[1]);
} catch {
images = JSON.parse(match[1].replace(/\\"/g, '"'));
}
return images.map((img, i) => ({
return json.result.images.map((img, i) => ({
url: img.url,
index: i,
headers: {

View File

@@ -4,7 +4,7 @@ class MangaDex {
this.apiUrl = "https://api.mangadex.org";
this.type = "book-board";
this.mediaType = "manga";
this.version = "1.0"
this.version = "1.1";
}
getHeaders() {
@@ -14,15 +14,226 @@ class MangaDex {
};
}
async search(queryObj) {
const query = queryObj.query?.trim() || "";
const limit = 25;
const offset = (1 - 1) * limit;
getFilters() {
return {
sort: {
label: "Sort By",
type: "select",
options: [
{ value: "relevance", label: "Relevance" },
{ value: "latestUploadedChapter", label: "Latest Upload" },
{ value: "followedCount", label: "Most Follows" },
{ value: "createdAt", label: "Created At" },
{ value: "updatedAt", label: "Updated At" },
{ value: "title", label: "Title" },
{ value: "year", label: "Year" },
{ value: "rating", label: "Rating" }
],
default: "relevance"
},
status: {
label: "Status",
type: "multiselect",
options: [
{ value: "ongoing", label: "Ongoing" },
{ value: "completed", label: "Completed" },
{ value: "hiatus", label: "Hiatus" },
{ value: "cancelled", label: "Cancelled" }
]
},
demographic: {
label: "Demographic",
type: "multiselect",
options: [
{ value: "shounen", label: "Shounen" },
{ value: "shoujo", label: "Shoujo" },
{ value: "seinen", label: "Seinen" },
{ value: "josei", label: "Josei" },
{ value: "none", label: "None" }
]
},
content_rating: {
label: "Content Rating",
type: "multiselect",
options: [
{ value: "safe", label: "Safe" },
{ value: "suggestive", label: "Suggestive" },
{ value: "erotica", label: "Erotica" },
{ value: "pornographic", label: "Pornographic" }
],
default: "safe,suggestive"
},
original_language: {
label: "Original Language",
type: "multiselect",
options: [
{ value: "ja", label: "Japanese" },
{ value: "zh", label: "Chinese" },
{ value: "ko", label: "Korean" }
]
},
tags_mode: {
label: "Tags Mode",
type: "select",
options: [
{ value: "AND", label: "AND (Match All)" },
{ value: "OR", label: "OR (Match Any)" }
],
default: "AND"
},
tags: {
label: "Tags",
type: "multiselect",
options: [
// Genres
{ value: "391b0423-d847-456f-aff0-8b0cfc03066b", label: "Action" },
{ value: "87cc87cd-a395-47af-b27a-93258283bbc6", label: "Adventure" },
{ value: "5920b825-4181-4a17-beeb-9918b0ff7a30", label: "Boys Love" },
{ value: "4d32cc48-9f00-4cca-9b5a-a839f0764984", label: "Comedy" },
{ value: "5ca48985-9a9d-4bd8-be29-80dc0303db72", label: "Crime" },
{ value: "b9af3a63-f058-46de-a9a0-e0c13906197a", label: "Drama" },
{ value: "cdc58593-87dd-415e-bbc0-2ec27bf404cc", label: "Fantasy" },
{ value: "a3c67850-4684-404e-9b7f-c69850ee5da6", label: "Girls Love" },
{ value: "33771934-028e-4cb3-8744-691e866a923e", label: "Historical" },
{ value: "cdad7e68-1419-41dd-bdce-27753074a640", label: "Horror" },
{ value: "ace04997-f6bd-436e-b261-779182193d3d", label: "Isekai" },
{ value: "81c836c9-914a-4eca-981a-560dad663e73", label: "Magical Girls" },
{ value: "50880a9d-5440-4732-9afb-8f457127e836", label: "Mecha" },
{ value: "c8cbe35b-1b2b-4a3f-9c37-db84c4514856", label: "Medical" },
{ value: "ee968100-4191-4968-93d3-f82d72be7e46", label: "Mystery" },
{ value: "b1e97889-25b4-4258-b28b-cd7f4d28ea9b", label: "Philosophical" },
{ value: "423e2eae-a7a2-4a8b-ac03-a8351462d71d", label: "Romance" },
{ value: "256c8bd9-4904-4360-bf4f-508a76d67183", label: "Sci-Fi" },
{ value: "e5301a23-ebd9-49dd-a0cb-2add944c7fe9", label: "Slice of Life" },
{ value: "69964a64-2f90-4d33-beeb-f3ed2875eb4c", label: "Sports" },
{ value: "7064a261-a137-4d3a-8848-2d385de3a99c", label: "Superhero" },
{ value: "07251805-a27e-4d59-b488-f0bfbec15168", label: "Thriller" },
{ value: "f8f62932-27da-4fe4-8ee1-6779a8c5edba", label: "Tragedy" },
{ value: "acc803a4-c95a-4c22-86fc-eb6b582d82a2", label: "Wuxia" },
// Themes
{ value: "e64f6742-c834-471d-8d72-dd51fc02b835", label: "Aliens" },
{ value: "3de8c75d-8ee3-48ff-98ee-e20a65c86451", label: "Animals" },
{ value: "ea2bc92d-1c26-4930-9b7c-d5c0dc1b6869", label: "Cooking" },
{ value: "9ab53f92-3eed-4e9b-903a-917c86035ee3", label: "Crossdressing" },
{ value: "da2d50ca-3018-4cc0-ac7a-6b7d472a29ea", label: "Delinquents" },
{ value: "39730448-9a5f-48a2-85b0-a70db87b1233", label: "Demons" },
{ value: "2bd2e8d0-f146-434a-9b51-fc9ff2c5fe6a", label: "Genderswap" },
{ value: "3bb26d85-09d5-4d2e-880c-c34b974339e9", label: "Ghosts" },
{ value: "fad12b5e-68ba-460e-b933-9ae8318f5b65", label: "Gyaru" },
{ value: "aafb99c1-7f60-43fa-b75f-fc9502ce29c7", label: "Harem" },
{ value: "5bd0e105-4481-44ca-b6e7-7544da56b1a3", label: "Incest" },
{ value: "2d1f5d56-a1e5-4d0d-a961-2193588b08ec", label: "Loli" },
{ value: "85daba54-a71c-4554-8a28-9901a8b0afad", label: "Mafia" },
{ value: "a1f53773-c69a-4ce5-8cab-fffcd90b1565", label: "Magic" },
{ value: "799c202e-7daa-44eb-9cf7-8a3c0441531e", label: "Martial Arts" },
{ value: "ac72833b-c4e9-4878-b9db-6c8a4a99444a", label: "Military" },
{ value: "dd1f77c5-dea9-4e2b-97ae-224af09caf99", label: "Monster Girls" },
{ value: "36fd93ea-e8b8-445e-b836-358f02b3d33d", label: "Monsters" },
{ value: "f42fbf9e-188a-447b-9fdc-f19dc1e4d685", label: "Music" },
{ value: "489dd859-9b61-4c37-af75-5b18e88daafc", label: "Ninja" },
{ value: "92d6d951-ca5e-429c-ac78-451071cbf064", label: "Office Workers" },
{ value: "df33b754-73a3-4c54-80e6-1a74a8058539", label: "Police" },
{ value: "9467335a-1b83-4497-9231-765337a00b96", label: "Post-Apocalyptic" },
{ value: "3b60b75c-a2d7-4860-ab56-05f391bb889c", label: "Psychological" },
{ value: "0bc90acb-ccc1-44ca-a34a-b9f3a73259d0", label: "Reincarnation" },
{ value: "65761a2a-415e-47f3-bef2-a9dababba7a6", label: "Reverse Harem" },
{ value: "81183756-1453-4c81-aa9e-f6e1b63be016", label: "Samurai" },
{ value: "caaa44eb-cd40-4177-b930-79d3ef2afe87", label: "School Life" },
{ value: "ddefd648-5140-4e5f-ba18-4eca4071d19b", label: "Shota" },
{ value: "eabc5b4c-6aff-42f3-b657-3e90cbd00b75", label: "Supernatural" },
{ value: "5fff9cde-849c-4d78-aab0-0d52b2ee1d25", label: "Survival" },
{ value: "292e862b-2d17-4062-90a2-0356caa4ae27", label: "Time Travel" },
{ value: "d7d1730f-6eb0-4ba6-9437-602cac38664c", label: "Vampires" },
{ value: "9438db5a-7e2a-4ac0-b39e-e0d95a34b8a8", label: "Video Games" },
{ value: "d14322ac-4d6f-4e9b-afd9-629d5f4d8a41", label: "Villainess" },
{ value: "631ef465-9aba-4afb-b0fc-ea10efe274a8", label: "Zombies" },
// Content
{ value: "b29d6a3d-1569-4e7a-8caf-7557bc92cd5d", label: "Gore" },
{ value: "97893a4c-12af-4dac-b6be-0dffb353568e", label: "Sexual Violence" }
]
}
};
}
async search({ query = "", page = 1, filters = {} }) {
const limit = 25;
const offset = (page - 1) * limit;
const url = new URL(`${this.apiUrl}/manga`);
// --- 1. Query ---
if (query.trim()) {
url.searchParams.append("title", query.trim());
}
// --- 2. Parámetros Fijos ---
url.searchParams.append("limit", limit.toString());
url.searchParams.append("offset", offset.toString());
url.searchParams.append("includes[]", "cover_art");
url.searchParams.append("availableTranslatedLanguage[]", "en");
// --- 3. Filtros Dinámicos ---
// A) Content Rating (Si no se especifica, usa safe+suggestive por defecto)
if (filters.content_rating) {
const ratings = String(filters.content_rating).split(",");
ratings.forEach(r => {
if (r.trim()) url.searchParams.append("contentRating[]", r.trim());
});
} else {
// Default behavior if not set
url.searchParams.append("contentRating[]", "safe");
url.searchParams.append("contentRating[]", "suggestive");
}
// B) Tags (includedTags)
if (filters.tags) {
const tags = String(filters.tags).split(",");
tags.forEach(t => {
if (t.trim()) url.searchParams.append("includedTags[]", t.trim());
});
}
// C) Tag Inclusion Mode
if (filters.tags_mode) {
url.searchParams.append("includedTagsMode", filters.tags_mode);
}
// D) Status
if (filters.status) {
const stats = String(filters.status).split(",");
stats.forEach(s => {
if (s.trim()) url.searchParams.append("status[]", s.trim());
});
}
// E) Demographic
if (filters.demographic) {
const demos = String(filters.demographic).split(",");
demos.forEach(d => {
if (d.trim()) url.searchParams.append("publicationDemographic[]", d.trim());
});
}
// F) Original Language
if (filters.original_language) {
const langs = String(filters.original_language).split(",");
langs.forEach(l => {
if (l.trim()) url.searchParams.append("originalLanguage[]", l.trim());
});
}
// G) Sort
// MangaDex usa order[KEY]=asc/desc
const sortVal = filters.sort || "relevance";
const orderDir = (sortVal === "title") ? "asc" : "desc";
// Si hay búsqueda por texto, relevance es útil, sino latestUploaded
url.searchParams.append(`order[${sortVal}]`, orderDir);
const url = `${this.apiUrl}/manga?title=${encodeURIComponent(query)}&limit=${limit}&offset=${offset}&includes[]=cover_art&contentRating[]=safe&contentRating[]=suggestive&availableTranslatedLanguage[]=en`;
try {
const response = await fetch(url, { headers: this.getHeaders() });
const response = await fetch(url.toString(), { headers: this.getHeaders() });
if (!response.ok) {
console.error(`MangaDex API Error: ${response.statusText}`);
return [];
@@ -45,7 +256,6 @@ class MangaDex {
? `https://uploads.mangadex.org/covers/${manga.id}/${coverFileName}.256.jpg`
: '';
return {
id: manga.id,
image: coverUrl,
@@ -94,8 +304,6 @@ class MangaDex {
? `https://uploads.mangadex.org/covers/${id}/${coverFile}.512.jpg`
: "";
const score100 = 0;
const statusMap = {
ongoing: "Ongoing",
completed: "Completed",
@@ -107,7 +315,7 @@ class MangaDex {
id,
title,
format: "Manga",
score: score100,
score: 0,
genres,
status: statusMap[attr.status] || "",
published: attr.year ? String(attr.year) : "???",
@@ -170,7 +378,7 @@ class MangaDex {
return chapters;
} catch (e) {
console.error("Error finding MangaDex chapters:", e);
return { chapters: [], cover: null };
return [];
}
}

View File

@@ -2,47 +2,162 @@ class MangaPill {
constructor() {
this.baseUrl = "https://mangapill.com";
this.type = "book-board";
this.version = "1.0";
this.version = "1.1";
this.mediaType = "manga";
}
async fetch(url) {
return fetch(url, {
headers: {
"User-Agent": "Mozilla/5.0",
Referer: this.baseUrl,
getFilters() {
return {
type: {
label: "Type",
type: "select",
options: [
{ value: "", label: "All" },
{ value: "manga", label: "Manga" },
{ value: "novel", label: "Novel" },
{ value: "one-shot", label: "One-Shot" },
{ value: "doujinshi", label: "Doujinshi" },
{ value: "manhwa", label: "Manhwa" },
{ value: "manhua", label: "Manhua" },
{ value: "oel", label: "OEL" }
]
},
});
status: {
label: "Status",
type: "select",
options: [
{ value: "", label: "All" },
{ value: "publishing", label: "Publishing" },
{ value: "finished", label: "Finished" },
{ value: "on hiatus", label: "On Hiatus" },
{ value: "discontinued", label: "Discontinued" },
{ value: "not yet published", label: "Not Yet Published" }
]
},
genre: {
label: "Genres",
type: "multiselect",
options: [
{ value: "Action", label: "Action" },
{ value: "Adventure", label: "Adventure" },
{ value: "Cars", label: "Cars" },
{ value: "Comedy", label: "Comedy" },
{ value: "Dementia", label: "Dementia" },
{ value: "Demons", label: "Demons" },
{ value: "Drama", label: "Drama" },
{ value: "Ecchi", label: "Ecchi" },
{ value: "Fantasy", label: "Fantasy" },
{ value: "Game", label: "Game" },
{ value: "Harem", label: "Harem" },
{ value: "Hentai", label: "Hentai" },
{ value: "Historical", label: "Historical" },
{ value: "Horror", label: "Horror" },
{ value: "Josei", label: "Josei" },
{ value: "Kids", label: "Kids" },
{ value: "Magic", label: "Magic" },
{ value: "Martial Arts", label: "Martial Arts" },
{ value: "Mecha", label: "Mecha" },
{ value: "Military", label: "Military" },
{ value: "Music", label: "Music" },
{ value: "Mystery", label: "Mystery" },
{ value: "Parody", label: "Parody" },
{ value: "Police", label: "Police" },
{ value: "Psychological", label: "Psychological" },
{ value: "Romance", label: "Romance" },
{ value: "Samurai", label: "Samurai" },
{ value: "School", label: "School" },
{ value: "Sci-Fi", label: "Sci-Fi" },
{ value: "Seinen", label: "Seinen" },
{ value: "Shoujo", label: "Shoujo" },
{ value: "Shoujo Ai", label: "Shoujo Ai" },
{ value: "Shounen", label: "Shounen" },
{ value: "Shounen Ai", label: "Shounen Ai" },
{ value: "Slice of Life", label: "Slice of Life" },
{ value: "Space", label: "Space" },
{ value: "Sports", label: "Sports" },
{ value: "Super Power", label: "Super Power" },
{ value: "Supernatural", label: "Supernatural" },
{ value: "Thriller", label: "Thriller" },
{ value: "Vampire", label: "Vampire" },
{ value: "Yaoi", label: "Yaoi" },
{ value: "Yuri", label: "Yuri" }
]
}
};
}
async search(queryObj) {
const q = queryObj.query || "";
const res = await this.fetch(
`${this.baseUrl}/search?q=${encodeURIComponent(q)}`
);
get headers() {
return {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Referer": this.baseUrl + "/"
};
}
async search({ query, page = 1, filters }) {
const url = new URL(`${this.baseUrl}/search`);
if (query) url.searchParams.set("q", query.trim());
url.searchParams.set("page", page.toString());
if (filters) {
if (filters.type) url.searchParams.set("type", filters.type);
if (filters.status) url.searchParams.set("status", filters.status);
if (filters.genre) {
// MangaPill espera ?genre=Action&genre=Comedy
const genres = String(filters.genre).split(',');
genres.forEach(g => {
if (g.trim()) url.searchParams.append("genre", g.trim());
});
}
}
const res = await fetch(url.toString(), { headers: this.headers });
if (!res.ok) throw new Error(`Search failed: ${res.status}`);
const html = await res.text();
const $ = this.cheerio.load(html);
const results = [];
$("div.container div.my-3.justify-end > div").each((_, el) => {
const link = $(el).find("a").attr("href");
if (!link) return;
// Selector actualizado basado en la extensión de Kotlin (.grid > div:not([class]))
// Buscamos dentro del grid de resultados
$(".grid > div:not([class]), div.container div.my-3.justify-end > div").each((_, el) => {
const a = $(el).find("a").first();
const href = a.attr("href");
if (!href) return;
const id = link.split("/manga/")[1].replace(/\//g, "$");
const title = $(el).find("div > a > div.mt-3").text().trim();
const image = $(el).find("a img").attr("data-src") || null;
// Extraer ID (manga/123/title -> 123$title)
const parts = href.split("/manga/");
if (parts.length < 2) return;
const id = parts[1].replace(/\//g, "$");
// Título: A veces es un div hermano, a veces dentro del anchor
let title = $(el).find("div > a > div").text().trim(); // Selector antiguo
if (!title) title = $(el).find("a:not(:first-child) > div").text().trim(); // Selector nuevo
if (!title) title = $(el).find(".font-bold, div[class*='font-bold']").text().trim(); // Fallback
const img = $(el).find("img").attr("data-src") || $(el).find("img").attr("src");
results.push({
id,
title,
image,
rating: null,
type: "book",
image: img || "",
type: "book"
});
});
return results;
// Eliminar duplicados si el selector doble atrapó cosas repetidas
const uniqueResults = [];
const seen = new Set();
for (const r of results) {
if (!seen.has(r.id)) {
seen.add(r.id);
uniqueResults.push(r);
}
}
return uniqueResults;
}
async getMetadata(id) {
@@ -52,83 +167,55 @@ class MangaPill {
redirect: "manual",
});
// follow redirect manually
if (res.status === 301 || res.status === 302) {
const loc = res.headers.get("location");
if (loc) {
res = await fetch(`${this.baseUrl}${loc}`, {
headers: this.headers,
});
res = await fetch(`${this.baseUrl}${loc}`, { headers: this.headers });
}
}
if (!res.ok) {
return {
id,
title: "",
format: "MANGA",
score: 0,
genres: "",
status: "unknown",
published: "",
summary: "",
chapters: "???",
image: null,
};
}
if (!res.ok) throw new Error("Failed to fetch metadata");
const html = await res.text();
const $ = this.cheerio.load(html);
const title = $("h1.font-bold").first().text().trim();
const summary = $("div.mb-3 p.text-sm").first().text().trim() || "";
const summary =
$("div.mb-3 p.text-sm").first().text().trim() || "";
const status =
$("label:contains('Status')")
.next("div")
.text()
.trim() || "unknown";
const published =
$("label:contains('Year')")
.next("div")
.text()
.trim() || "";
// Status y Published suelen estar en labels
const status = $("label:contains('Status')").next("div").text().trim().toLowerCase() || "unknown";
const published = $("label:contains('Year')").next("div").text().trim() || "";
const genres = [];
$("label:contains('Genres')")
.parent()
.find("a")
.each((_, a) => genres.push($(a).text().trim()));
$("a[href*='genre']").each((_, el) => {
genres.push($(el).text().trim());
});
const image =
$("img[data-src]").first().attr("data-src") || null;
const image = $("img[data-src]").first().attr("data-src") || "";
return {
id,
title,
format: "MANGA",
score: 0,
genres: genres.join(", "),
genres: genres, // Array de strings
status,
published,
summary,
chapters: "???",
chapters: 0, // Se calcula dinámicamente si es necesario
image
};
}
async findChapters(mangaId) {
const uriId = mangaId.replace(/\$/g, "/");
const res = await this.fetch(`${this.baseUrl}/manga/${uriId}`);
const res = await fetch(`${this.baseUrl}/manga/${uriId}`, { headers: this.headers });
const html = await res.text();
const $ = this.cheerio.load(html);
const chapters = [];
$("div#chapters a").each((_, el) => {
$("#chapters > div > a").each((_, el) => {
const href = $(el).attr("href");
if (!href) return;
@@ -153,24 +240,22 @@ class MangaPill {
async findChapterPages(chapterId) {
const uriId = chapterId.replace(/\$/g, "/");
const res = await this.fetch(`${this.baseUrl}/chapters/${uriId}`);
const res = await fetch(`${this.baseUrl}/chapters/${uriId}`, { headers: this.headers });
const html = await res.text();
const $ = this.cheerio.load(html);
const pages = [];
$("chapter-page").each((i, el) => {
const img = $(el).find("div picture img").attr("data-src");
$("picture img").each((i, el) => {
const img = $(el).attr("data-src");
if (!img) return;
pages.push({
url: img,
index: i,
headers: {
Referer: "https://mangapill.com/",
Origin: "https://mangapill.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
Accept: "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
"Referer": this.baseUrl + "/",
"User-Agent": this.headers["User-Agent"]
},
});
});

View File

@@ -2,10 +2,67 @@ class NHentai {
constructor() {
this.baseUrl = "https://nhentai.net";
this.type = "book-board";
this.version = "1.1";
this.version = "1.2";
this.mediaType = "manga";
}
getFilters() {
return {
sort: {
label: "Order",
type: "select",
options: [
{ value: "date", label: "Recent" },
{ value: "popular", label: "Popular: All time" },
{ value: "popular-month", label: "Popular: Month" },
{ value: "popular-week", label: "Popular: Week" },
{ value: "popular-today", label: "Popular: Today" }
],
default: "date"
},
tags: {
label: "Tags (separated by comma)",
type: "text",
placeholder: "ej. big breasts, stocking"
},
categories: {
label: "Categories",
type: "text",
placeholder: "ej. doujinshi, manga"
},
groups: {
label: "Groups",
type: "text",
placeholder: "ej. fakku"
},
artists: {
label: "Artists",
type: "text",
placeholder: "ej. shindo l"
},
parodies: {
label: "Parodies",
type: "text",
placeholder: "ej. naruto"
},
characters: {
label: "Characters",
type: "text",
placeholder: "ej. sakura haruno"
},
pages: {
label: "Pages (ej. >20)",
type: "text",
placeholder: ">20"
},
uploaded: {
label: "Uploaded (ej. >20d)",
type: "text",
placeholder: ">20d"
}
};
}
shortenTitle(title) {
return title.replace(/(\[[^]]*]|[({][^)}]*[)}])/g, "").trim();
}
@@ -26,16 +83,62 @@ class NHentai {
return JSON.parse(unicodeFixed);
}
async search({ query = "", page = 1 }) {
if (query.startsWith("id:") || (!isNaN(query) && query.length <= 7)) {
async search({ query = "", page = 1, filters = null }) {
if (query.startsWith("id:") || (!isNaN(query) && query.length <= 7 && query.length > 0)) {
return [await this.getMetadata(this.parseId(query))];
}
const url = `${this.baseUrl}/search/?q=${encodeURIComponent(query)}&page=${page}`;
let advQuery = "";
let sortParam = "";
if (filters) {
const textFilters = [
{ key: "tags", prefix: "tag" },
{ key: "categories", prefix: "category" },
{ key: "groups", prefix: "group" },
{ key: "artists", prefix: "artist" },
{ key: "parodies", prefix: "parody" },
{ key: "characters", prefix: "character" },
{ key: "uploaded", prefix: "uploaded", noQuote: true },
{ key: "pages", prefix: "pages", noQuote: true }
];
textFilters.forEach(({ key, prefix, noQuote }) => {
if (filters[key]) {
const terms = filters[key].split(",");
terms.forEach(term => {
const t = term.trim();
if (!t) return;
let currentPrefix = prefix;
let currentTerm = t;
let isExclusion = false;
if (t.startsWith("-")) {
isExclusion = true;
currentTerm = t.substring(1);
}
advQuery += ` ${isExclusion ? "-" : ""}${currentPrefix}:`;
advQuery += noQuote ? currentTerm : `"${currentTerm}"`;
});
}
});
if (filters.sort && filters.sort !== "date") {
sortParam = `&sort=${filters.sort}`;
}
}
const finalQuery = (query + " " + advQuery).trim() || '""';
const url = `${this.baseUrl}/search/?q=${encodeURIComponent(finalQuery)}&page=${page}${sortParam}`;
const { result } = await this.scrape(
url,
page =>
page.evaluate(() => document.documentElement.innerHTML),
page => page.evaluate(() => document.documentElement.innerHTML),
{ waitSelector: ".gallery" }
);

View File

@@ -3,18 +3,663 @@ class NovelFire {
this.baseUrl = "https://novelfire.net";
this.type = "book-board";
this.mediaType = "ln";
this.version = "1.1"
this.version = "1.2";
}
async search(queryObj) {
const query = queryObj.query;
getFilters() {
return {
sort: {
label: "Sort By",
type: "select",
options: [
{ value: "bookmark", label: "Bookmark Count (Most)" },
{ value: "date", label: "Last Updated (Newest)" },
{ value: "rank-top", label: "Rank (Top)" },
{ value: "rating-score-top", label: "Rating Score (Top)" },
{ value: "review", label: "Review Count (Most)" },
{ value: "comment", label: "Comment Count (Most)" },
{ value: "today-view", label: "Today Views (Most)" },
{ value: "monthly-view", label: "Monthly Views (Most)" },
{ value: "total-view", label: "Total Views (Most)" },
{ value: "chapter-count-most", label: "Chapter Count (Most)" },
{ value: "abc", label: "Title (A-Z)" },
{ value: "cba", label: "Title (Z-A)" }
],
default: "bookmark"
},
status: {
label: "Status",
type: "select",
options: [
{ value: "-1", label: "All" },
{ value: "1", label: "Completed" },
{ value: "0", label: "Ongoing" }
],
default: "-1"
},
chapters: {
label: "Chapter Count",
type: "select",
options: [
{ value: "0", label: "All" },
{ value: "1,49", label: "< 50" },
{ value: "50,100", label: "50 - 100" },
{ value: "100,200", label: "100 - 200" },
{ value: "200,500", label: "200 - 500" },
{ value: "500,1000", label: "500 - 1000" },
{ value: "1001,1000000", label: "> 1000" }
],
default: "0"
},
// Géneros (Categories)
genres: {
label: "Genres (Categories)",
type: "multiselect",
options: [
{ value: "1", label: "Action" },
{ value: "2", label: "Adventure" },
{ value: "3", label: "Comedy" },
{ value: "4", label: "Drama" },
{ value: "5", label: "Ecchi" },
{ value: "6", label: "Fantasy" },
{ value: "7", label: "Harem" },
{ value: "8", label: "Historical" },
{ value: "9", label: "Horror" },
{ value: "10", label: "Josei" },
{ value: "11", label: "Martial Arts" },
{ value: "12", label: "Mature" },
{ value: "13", label: "Mecha" },
{ value: "14", label: "Mystery" },
{ value: "15", label: "Psychological" },
{ value: "16", label: "Romance" },
{ value: "17", label: "School Life" },
{ value: "18", label: "Sci-fi" },
{ value: "19", label: "Seinen" },
{ value: "20", label: "Shoujo" },
{ value: "21", label: "Shoujo Ai" },
{ value: "22", label: "Shounen" },
{ value: "23", label: "Shounen Ai" },
{ value: "24", label: "Slice of Life" },
{ value: "25", label: "Smut" },
{ value: "26", label: "Sports" },
{ value: "27", label: "Supernatural" },
{ value: "28", label: "Tragedy" },
{ value: "29", label: "Wuxia" },
{ value: "30", label: "Xianxia" },
{ value: "31", label: "Xuanhuan" },
{ value: "32", label: "Yaoi" },
{ value: "33", label: "Yuri" },
{ value: "34", label: "Adult" },
{ value: "35", label: "Gender Bender" }
]
},
// Etiquetas (Tags) - Lista Masiva
tags: {
label: "Tags",
type: "multiselect",
options: [
{ value: "10", label: "Unique Cultivation Technique" }, { value: "11", label: "Fast Cultivation" }, { value: "12", label: "Marriage" },
{ value: "13", label: "Hard-Working Protagonist" }, { value: "14", label: "Gods" }, { value: "15", label: "Monsters" },
{ value: "16", label: "Weak to Strong" }, { value: "17", label: "Broken Engagement" }, { value: "18", label: "Strong Love Interests" },
{ value: "19", label: "Romantic Subplot" }, { value: "20", label: "Power Couple" }, { value: "21", label: "Tragic Past" },
{ value: "22", label: "Demons" }, { value: "23", label: "Beautiful Female Lead" }, { value: "24", label: "Demon Lord" },
{ value: "25", label: "Genius Protagonist" }, { value: "26", label: "Bloodlines" }, { value: "27", label: "Sword Wielder" },
{ value: "28", label: "Black Belly" }, { value: "29", label: "Boss-Subordinate Relationship" }, { value: "30", label: "Money Grubber" },
{ value: "31", label: "Bickering Couple" }, { value: "32", label: "Calm Protagonist" }, { value: "33", label: "Female Protagonist" },
{ value: "34", label: "Childcare" }, { value: "35", label: "Handsome Male Lead" }, { value: "36", label: "Modern Day" },
{ value: "37", label: "Magic Formations" }, { value: "38", label: "Beast Companions" }, { value: "39", label: "Immortals" },
{ value: "40", label: "Archery" }, { value: "41", label: "Cunning Protagonist" }, { value: "42", label: "Ruthless Protagonist" },
{ value: "43", label: "Body Tempering" }, { value: "44", label: "Clever Protagonist" }, { value: "45", label: "Pets" },
{ value: "46", label: "Multiple Realms" }, { value: "47", label: "Near-Death Experience" }, { value: "48", label: "Artifacts" },
{ value: "49", label: "Beasts" }, { value: "50", label: "Buddhism" }, { value: "51", label: "Crafting" },
{ value: "52", label: "Alchemy" }, { value: "53", label: "Schemes And Conspiracies" }, { value: "54", label: "Determined Protagonist" },
{ value: "55", label: "Male Protagonist" }, { value: "56", label: "Non-humanoid Protagonist" }, { value: "57", label: "Demonic Cultivation Technique" },
{ value: "58", label: "Trap" }, { value: "59", label: "Cruel Characters" }, { value: "60", label: "Arrogant Characters" },
{ value: "61", label: "Evil Organizations" }, { value: "62", label: "Wars" }, { value: "63", label: "Strength-based Social Hierarchy" },
{ value: "64", label: "Artifact Crafting" }, { value: "65", label: "Dragons" }, { value: "66", label: "Late Romance" },
{ value: "67", label: "Revenge" }, { value: "68", label: "Doctors" }, { value: "69", label: "Reincarnation" },
{ value: "70", label: "Second Chance" }, { value: "71", label: "Rebirth" }, { value: "72", label: "Showbiz" },
{ value: "73", label: "Cute Children" }, { value: "74", label: "Previous Life Talent" }, { value: "75", label: "Celebrities" },
{ value: "76", label: "Acting" }, { value: "77", label: "Smart Couple" }, { value: "78", label: "Older Love Interests" },
{ value: "79", label: "Caring Protagonist" }, { value: "80", label: "Protagonist Falls in Love First" }, { value: "81", label: "Politics" },
{ value: "82", label: "Devoted Love Interests" }, { value: "83", label: "Guardian Relationship" }, { value: "84", label: "Ancient China" },
{ value: "85", label: "Character Growth" }, { value: "86", label: "Time Skip" }, { value: "87", label: "Nobles" },
{ value: "88", label: "Adapted to Drama CD" }, { value: "89", label: "Seme Protagonist" }, { value: "90", label: "Pragmatic Protagonist" },
{ value: "91", label: "Slow Romance" }, { value: "92", label: "Royalty" }, { value: "93", label: "Loyal Subordinates" },
{ value: "94", label: "Age Progression" }, { value: "95", label: "Cultivation" }, { value: "96", label: "Card Games" },
{ value: "97", label: "Adapted to Anime" }, { value: "98", label: "Game Elements" }, { value: "99", label: "Average-looking Protagonist" },
{ value: "100", label: "Firearms" }, { value: "101", label: "Fanfiction" }, { value: "102", label: "Survival Game" },
{ value: "103", label: "Betrayal" }, { value: "104", label: "Hunters" }, { value: "105", label: "Aliens" },
{ value: "106", label: "Evolution" }, { value: "107", label: "Apocalypse" }, { value: "108", label: "Transported to Another World" },
{ value: "109", label: "Military" }, { value: "110", label: "Adapted to Manhua" }, { value: "111", label: "Vampires" },
{ value: "112", label: "Movies" }, { value: "113", label: "Alternate World" }, { value: "114", label: "Ghosts" },
{ value: "115", label: "Eidetic Memory" }, { value: "116", label: "Limited Lifespan" }, { value: "117", label: "Misunderstandings" },
{ value: "118", label: "Cheats" }, { value: "119", label: "Fast Learner" }, { value: "120", label: "Souls" },
{ value: "121", label: "Jack of All Trades" }, { value: "122", label: "Transmigration" }, { value: "123", label: "Sudden Strength Gain" },
{ value: "124", label: "Parody" }, { value: "125", label: "Overpowered Protagonist" }, { value: "126", label: "Poisons" },
{ value: "127", label: "Library" }, { value: "128", label: "Dense Protagonist" }, { value: "129", label: "Protagonist with Multiple Bodies" },
{ value: "130", label: "Master-Disciple Relationship" }, { value: "131", label: "Shy Characters" }, { value: "132", label: "Manipulative Characters" },
{ value: "133", label: "Teachers" }, { value: "134", label: "Academy" }, { value: "135", label: "Pill Concocting" },
{ value: "136", label: "Enlightenment" }, { value: "137", label: "Possessive Characters" }, { value: "138", label: "Shameless Protagonist" },
{ value: "139", label: "Transported into Another World" }, { value: "140", label: "Sharp-tongued Characters" }, { value: "141", label: "Male Yandere" },
{ value: "142", label: "Complex Family Relationships" }, { value: "143", label: "Couple Growth" }, { value: "144", label: "Abusive Characters" },
{ value: "145", label: "Cold Love Interests" }, { value: "146", label: "Love Interest Falls in Love First" }, { value: "147", label: "Amnesia" },
{ value: "148", label: "Forced into a Relationship" }, { value: "149", label: "Cross-dressing" }, { value: "150", label: "Personality Changes" },
{ value: "151", label: "Weak Protagonist" }, { value: "152", label: "Technological Gap" }, { value: "153", label: "Kingdom Building" },
{ value: "154", label: "Economics Engineer" }, { value: "155", label: "Management" }, { value: "156", label: "Army" },
{ value: "157", label: "Fantasy World" }, { value: "158", label: "Discrimination" }, { value: "159", label: "Multiple POV" },
{ value: "160", label: "Strategic Battles" }, { value: "161", label: "Leadership" }, { value: "162", label: "Magic" },
{ value: "163", label: "Kingdoms Knights" }, { value: "164", label: "Domestic Affairs" }, { value: "165", label: "Early Romance" },
{ value: "166", label: "Modern Knowledge" }, { value: "167", label: "Stoic Characters" }, { value: "168", label: "Army Building" },
{ value: "169", label: "Medieval" }, { value: "170", label: "Mature Protagonist" }, { value: "171", label: "Depictions of Cruelty" },
{ value: "172", label: "Religions" }, { value: "173", label: "Industrialization" }, { value: "174", label: "Business Management" },
{ value: "175", label: "Pregnancy" }, { value: "176", label: "Jealousy" }, { value: "177", label: "Fleet Battles" },
{ value: "178", label: "Elves" }, { value: "179", label: "MMORPG" }, { value: "180", label: "Dungeons" },
{ value: "181", label: "Virtual Reality" }, { value: "182", label: "Battle Competition" }, { value: "183", label: "Game Ranking System" },
{ value: "184", label: "Dwarfs" }, { value: "185", label: "Poor to Rich" }, { value: "186", label: "Hiding True Identity" },
{ value: "187", label: "Spatial Manipulation" }, { value: "188", label: "Monster Society" }, { value: "189", label: "Sword And Magic" },
{ value: "190", label: "Beastkin" }, { value: "191", label: "Outer Space" }, { value: "192", label: "Spaceship" },
{ value: "193", label: "Businessmen" }, { value: "194", label: "Mercenaries" }, { value: "195", label: "Magical Space" },
{ value: "196", label: "Knights" }, { value: "197", label: "Level System" }, { value: "198", label: "Dragon Slayers" },
{ value: "199", label: "Previous Life" }, { value: "200", label: "Skill Books" }, { value: "201", label: "Creatures" },
{ value: "202", label: "Store Owner" }, { value: "203", label: "Famous Protagonist" }, { value: "204", label: "Gamers" },
{ value: "205", label: "Lucky Protagonist" }, { value: "206", label: "Blacksmith" }, { value: "207", label: "Friendship" },
{ value: "208", label: "Talent" }, { value: "209", label: "Fantasy" }, { value: "210", label: "Guilds" },
{ value: "211", label: "Aristocracy" }, { value: "212", label: "Harem" }, { value: "213", label: "ArtifactCrafting" },
{ value: "214", label: "BodyTempering" }, { value: "215", label: "BeautifulFemaleLead" }, { value: "216", label: "Strategist" },
{ value: "217", label: "Clubs" }, { value: "218", label: "Adapted to Drama" }, { value: "219", label: "e-Sports" },
{ value: "220", label: "Grinding" }, { value: "221", label: "Carefree Protagonist" }, { value: "222", label: "Past Plays a Big Role Protagonist" },
{ value: "223", label: "Confident Protagonist" }, { value: "224", label: "Secret Identity" }, { value: "225", label: "Strong from the Start" },
{ value: "226", label: "Wealthy Characters" }, { value: "227", label: "Mutated Creatures" }, { value: "228", label: "Underestimated Protagonist" },
{ value: "229", label: "Battle Academy" }, { value: "230", label: "Hiding True Abilities" }, { value: "231", label: "Enemies Become Allies" },
{ value: "232", label: "Adopted Children" }, { value: "233", label: "Mysterious Family Background" }, { value: "234", label: "Younger Sisters" },
{ value: "235", label: "Genetic Modifications" }, { value: "236", label: "Futuristic Setting" }, { value: "237", label: "Reverse Harem" },
{ value: "238", label: "Doting Love Interests" }, { value: "239", label: "Childhood Love" }, { value: "240", label: "Popular Love Interests" },
{ value: "241", label: "Hidden Abilities" }, { value: "242", label: "Kuudere" }, { value: "243", label: "Gore" },
{ value: "244", label: "Rape" }, { value: "245", label: "Special Abilities" }, { value: "246", label: "Cold Protagonist" },
{ value: "247", label: "Spirits" }, { value: "248", label: "Prophecies" }, { value: "249", label: "Godly Powers" },
{ value: "250", label: "Inheritance" }, { value: "251", label: "Martial Spirits" }, { value: "252", label: "Transplanted Memories" },
{ value: "253", label: "Sexual Cultivation Technique" }, { value: "254", label: "Polygamy" }, { value: "255", label: "Murders" },
{ value: "256", label: "Skill Assimilation" }, { value: "257", label: "Reincarnated in a Game World" }, { value: "258", label: "Assassins" },
{ value: "259", label: "Action" }, { value: "260", label: "Transported into a Game World" }, { value: "261", label: "Engineer" },
{ value: "262", label: "Adventurers" }, { value: "263", label: "Narcissistic Protagonist" }, { value: "264", label: "Secret Organizations" },
{ value: "265", label: "Multiple Identities" }, { value: "266", label: "Cautious Protagonist" }, { value: "267", label: "Accelerated Growth" },
{ value: "268", label: "Gunfighters" }, { value: "269", label: "Cosmic Wars" }, { value: "270", label: "Selfish Protagonist" },
{ value: "271", label: "Artificial Intelligence" }, { value: "272", label: "Arms Dealers" }, { value: "273", label: "Biochip" },
{ value: "274", label: "Automatons" }, { value: "275", label: "Mob Protagonist" }, { value: "276", label: "Magical Technology" },
{ value: "277", label: "Nationalism" }, { value: "278", label: "Comedic Undertone" }, { value: "279", label: "Divorce" },
{ value: "280", label: "Arranged Marriage" }, { value: "281", label: "Long Separations" }, { value: "282", label: "Rape Victim Becomes Lover" },
{ value: "283", label: "Secret Relationship" }, { value: "284", label: "Secret Crush" }, { value: "285", label: "Secrets" },
{ value: "286", label: "Death" }, { value: "287", label: "Love at First Sight" }, { value: "288", label: "Secretive Protagonist" },
{ value: "289", label: "Tsundere" }, { value: "290", label: "Sexual Abuse" }, { value: "291", label: "College/University" },
{ value: "292", label: "Eye Powers" }, { value: "293", label: "Sect Development" }, { value: "294", label: "Slaves" },
{ value: "295", label: "Race Change" }, { value: "296", label: "Heterochromia" }, { value: "297", label: "God Protagonist" },
{ value: "298", label: "Fox Spirits" }, { value: "299", label: "Soul Power" }, { value: "300", label: "Elderly Protagonist" },
{ value: "301", label: "Sibling Rivalry" }, { value: "302", label: "Hated Protagonist" }, { value: "303", label: "Evil Protagonist" },
{ value: "304", label: "Dark" }, { value: "305", label: "Merchants" }, { value: "306", label: "Orphans" },
{ value: "307", label: "Magic Beasts" }, { value: "308", label: "Philosophical" }, { value: "309", label: "Proactive Protagonist" },
{ value: "310", label: "Antihero Protagonist" }, { value: "311", label: "Appearance Changes" }, { value: "312", label: "Appearance Different from Actual Age" },
{ value: "313", label: "Dao Comprehension" }, { value: "314", label: "Apathetic Protagonist" }, { value: "315", label: "Reincarnated in Another World" },
{ value: "316", label: "Twins" }, { value: "317", label: "Heavenly Tribulation" }, { value: "318", label: "Interconnected Storylines" },
{ value: "319", label: "World Travel" }, { value: "320", label: "Loner Protagonist" }, { value: "321", label: "Time Manipulation" },
{ value: "322", label: "Fellatio" }, { value: "323", label: "First-time Intercourse" }, { value: "324", label: "Abandoned Children" },
{ value: "325", label: "Strong to Stronger" }, { value: "326", label: "R-18" }, { value: "327", label: "Male MC" },
{ value: "328", label: "Hidden Gem" }, { value: "329", label: "Western Fantasy" }, { value: "330", label: "Protagonist Strong from the Start" },
{ value: "331", label: "Easy Going Life" }, { value: "332", label: "Lazy Protagonist" }, { value: "333", label: "Family Conflict" },
{ value: "334", label: "Poor Protagonist" }, { value: "335", label: "Adultery" }, { value: "336", label: "Investigations" },
{ value: "337", label: "Gangs" }, { value: "338", label: "Racism" }, { value: "339", label: "Single Parent" },
{ value: "340", label: "Inscriptions" }, { value: "341", label: "Student-Teacher Relationship" }, { value: "342", label: "Clever Protagonist Cultivation" },
{ value: "343", label: "Returning from Another World" }, { value: "344", label: "Bullying" }, { value: "345", label: "Urban" },
{ value: "346", label: "Honest Protagonist" }, { value: "347", label: "See edit history" }, { value: "348", label: "Death of Loved Ones" },
{ value: "349", label: "Evil Gods" }, { value: "350", label: "Friends Become Enemies" }, { value: "351", label: "Outdoor Intercourse" },
{ value: "352", label: "Perverted Protagonist" }, { value: "353", label: "Zombies" }, { value: "354", label: "Empires" },
{ value: "355", label: "Pill Based Cultivation" }, { value: "356", label: "Economics" }, { value: "357", label: "Gate to Another World" },
{ value: "358", label: "Herbalist" }, { value: "359", label: "Insects" }, { value: "360", label: "Low-key Protagonist" },
{ value: "361", label: "Medical Knowledge" }, { value: "362", label: "Modern World" }, { value: "363", label: "Organized Crime" },
{ value: "364", label: "Absent Parents" }, { value: "365", label: "Cute Protagonist" }, { value: "366", label: "Genies" },
{ value: "367", label: "Martial arts" }, { value: "368", label: "Mythical Beasts" }, { value: "369", label: "Spear Wielder" },
{ value: "370", label: "Dao Companion" }, { value: "371", label: "Demi-Humans" }, { value: "372", label: "World Tree" },
{ value: "373", label: "Adapted to Manga" }, { value: "374", label: "Contracts" }, { value: "375", label: "Human Experimentation" },
{ value: "376", label: "Humanoid Protagonist" }, { value: "377", label: "Pharmacist" }, { value: "378", label: "Sealed Power" },
{ value: "379", label: "Spirit Advisor" }, { value: "380", label: "Thieves" }, { value: "381", label: "Ugly to Beautiful" },
{ value: "382", label: "Phoenixes" }, { value: "383", label: "Sister Complex" }, { value: "384", label: "Summoning Magic" },
{ value: "385", label: "Hackers" }, { value: "386", label: "Programmer" }, { value: "387", label: "Stubborn Protagonist" },
{ value: "388", label: "Drugs" }, { value: "389", label: "Human-Nonhuman Relationship" }, { value: "390", label: "Hypnotism" },
{ value: "391", label: "Quirky Characters" }, { value: "392", label: "Torture" }, { value: "393", label: "Chefs" },
{ value: "394", label: "Cooking" }, { value: "395", label: "Restaurant" }, { value: "396", label: "System Administrator" },
{ value: "397", label: "Unique Weapon User" }, { value: "398", label: "Mutations" }, { value: "399", label: "Post-apocalyptic" },
{ value: "400", label: "Clan Building" }, { value: "401", label: "Legends" }, { value: "402", label: "Possession" },
{ value: "403", label: "Righteous Protagonist" }, { value: "404", label: "Healers" }, { value: "405", label: "Necromancer" },
{ value: "406", label: "Parallel Worlds" }, { value: "407", label: "Charismatic Protagonist" }, { value: "408", label: "Playful Protagonist" },
{ value: "409", label: "Shounen-Ai Subplot" }, { value: "410", label: "Harem-seeking Protagonist" }, { value: "411", label: "Hot-blooded Protagonist" },
{ value: "412", label: "Imperial Harem" }, { value: "413", label: "Masturbation" }, { value: "414", label: "Naive Protagonist" },
{ value: "415", label: "Reverse Rape" }, { value: "416", label: "Books" }, { value: "417", label: "Lottery" },
{ value: "418", label: "Poetry" }, { value: "419", label: "Writers" }, { value: "420", label: "Elemental Magic" },
{ value: "421", label: "Kingdoms" }, { value: "422", label: "Affair" }, { value: "423", label: "Charming Protagonist" },
{ value: "424", label: "Scientists" }, { value: "425", label: "Singers" }, { value: "426", label: "Childhood Friends" },
{ value: "427", label: "Childhood Promise" }, { value: "428", label: "Forced Marriage" }, { value: "429", label: "Doting Older Siblings" },
{ value: "430", label: "BDSM" }, { value: "431", label: "Masochistic Characters" }, { value: "432", label: "Teamwork" },
{ value: "433", label: "Threesome" }, { value: "434", label: "Cowardly Protagonist" }, { value: "435", label: "Unlucky Protagonist" },
{ value: "436", label: "Harsh Training" }, { value: "437", label: "Psychic Powers" }, { value: "438", label: "Druids" },
{ value: "439", label: "Enemies Become Lovers" }, { value: "440", label: "Maids" }, { value: "441", label: "Master-Servant Relationship" },
{ value: "442", label: "Cannibalism" }, { value: "443", label: "Corruption" }, { value: "444", label: "Farming" },
{ value: "445", label: "Generals" }, { value: "446", label: "Mind Control" }, { value: "447", label: "Monster Tamer" },
{ value: "448", label: "Prostitutes" }, { value: "449", label: "Sex Slaves" }, { value: "450", label: "Survival" },
{ value: "451", label: "Living Alone" }, { value: "452", label: "System" }, { value: "453", label: "Ancient Times" },
{ value: "454", label: "Fallen Nobility" }, { value: "455", label: "Past Plays a Big Role" }, { value: "456", label: "Past Trauma" },
{ value: "457", label: "Detectives" }, { value: "458", label: "Sickly Characters" }, { value: "459", label: "Fairies" },
{ value: "460", label: "Goblins" }, { value: "461", label: "Golems" }, { value: "462", label: "Slave Harem" },
{ value: "463", label: "Wizards" }, { value: "464", label: "Ability Steal" }, { value: "465", label: "Music" },
{ value: "466", label: "Mythology" }, { value: "467", label: "Trickster" }, { value: "468", label: "Anal" },
{ value: "469", label: "Clingy Lover" }, { value: "470", label: "Cousins" }, { value: "471", label: "Handjob" },
{ value: "472", label: "Photography" }, { value: "473", label: "Siblings" }, { value: "474", label: "Siblings Not Related by Blood" },
{ value: "475", label: "Yandere" }, { value: "476", label: "Blood Manipulation" }, { value: "477", label: "Tribal Society" },
{ value: "478", label: "Adopted Protagonist" }, { value: "479", label: "Incest" }, { value: "480", label: "Unrequited Love" },
{ value: "481", label: "Fallen Angels" }, { value: "482", label: "Goddesses" }, { value: "483", label: "Succubus" },
{ value: "484", label: "Terrorists" }, { value: "485", label: "Dreams" }, { value: "486", label: "World Hopping" },
{ value: "487", label: "Mysterious Past" }, { value: "488", label: "Terminal Illness" }, { value: "489", label: "Transported Modern Structure" },
{ value: "490", label: "Brotherhood" }, { value: "491", label: "Douluo Dalu" }, { value: "492", label: "European Ambience" },
{ value: "493", label: "Evil Religions" }, { value: "494", label: "Familiars" }, { value: "495", label: "Fated Lovers" },
{ value: "496", label: "Transformation Ability" }, { value: "497", label: "Fan-fiction" }, { value: "498", label: "Servants" },
{ value: "499", label: "Stockholm Syndrome" }, { value: "500", label: "Fantasy Magic" }, { value: "501", label: "Slow Growth at Start" },
{ value: "502", label: "Blind Protagonist" }, { value: "503", label: "Mpreg" }, { value: "504", label: "Familial Love" },
{ value: "505", label: "Multiple Reincarnated Individuals" }, { value: "506", label: "Curses" }, { value: "507", label: "Age Regression" },
{ value: "508", label: "Polite Protagonist" }, { value: "509", label: "Androgynous Characters" }, { value: "510", label: "Depression" },
{ value: "511", label: "Lawyers" }, { value: "512", label: "Seven Deadly Sins" }, { value: "513", label: "Twisted Personality" },
{ value: "514", label: "Polyandry" }, { value: "515", label: "Werebeasts" }, { value: "516", label: "Overprotective Siblings" },
{ value: "517", label: "Kidnappings" }, { value: "518", label: "Doting Parents" }, { value: "519", label: "Family" },
{ value: "520", label: "Models" }, { value: "521", label: "Clumsy Love Interests" }, { value: "522", label: "Love Triangles" },
{ value: "523", label: "Persistent Love Interests" }, { value: "524", label: "Sentient Objects" }, { value: "525", label: "Unique Weapons" },
{ value: "526", label: "Multiple Transported Individuals" }, { value: "527", label: "Obsessive Love" }, { value: "528", label: "Xuanhuan" },
{ value: "529", label: "Fantasy Creatures" }, { value: "530", label: "God-human Relationship" }, { value: "531", label: "Lost Civilizations" },
{ value: "532", label: "Campus Love" }, { value: "533", label: "Naruto" }, { value: "534", label: "Artists" },
{ value: "535", label: "Fearless Protagonist" }, { value: "536", label: "Skill Creation" }, { value: "537", label: "First Love" },
{ value: "538", label: "Lovers Reunited" }, { value: "539", label: "Soldiers" }, { value: "540", label: "Unconditional Love" },
{ value: "541", label: "Saving the World" }, { value: "542", label: "Superpowers" }, { value: "543", label: "Wuxia" },
{ value: "544", label: "Dolls/Puppets" }, { value: "545", label: "Football" }, { value: "546", label: "Villainess Noble Girls" },
{ value: "547", label: "Bodyguards" }, { value: "548", label: "Netori" }, { value: "549", label: "Nudity" },
{ value: "550", label: "Paizuri" }, { value: "551", label: "Family Business" }, { value: "552", label: "Pirates" },
{ value: "553", label: "Chuunibyou" }, { value: "554", label: "Lack of Common Sense" }, { value: "555", label: "Seduction" },
{ value: "556", label: "beautiful heroine" }, { value: "557", label: "Time Travel" }, { value: "558", label: "Heartwarming" },
{ value: "559", label: "Interdimensional Travel" }, { value: "560", label: "Parent Complex" }, { value: "561", label: "Precognition" },
{ value: "562", label: "Time Paradox" }, { value: "563", label: "Gambling" }, { value: "564", label: "Orcs" },
{ value: "565", label: "Summoned Hero" }, { value: "566", label: "Manly Gay Couple" }, { value: "567", label: "Power Struggle" },
{ value: "568", label: "Cute Story" }, { value: "569", label: "Dungeon Master" }, { value: "570", label: "Brother Complex" },
{ value: "571", label: "Cryostasis" }, { value: "572", label: "Different Social Status" }, { value: "573", label: "Student Council" },
{ value: "574", label: "Autism" }, { value: "575", label: "Childish Protagonist" }, { value: "576", label: "Genderless Protagonist" },
{ value: "577", label: "Half-human Protagonist" }, { value: "578", label: "Summoner" }, { value: "579", label: "Online Romance" },
{ value: "580", label: "Younger Love Interests" }, { value: "581", label: "Thriller" }, { value: "582", label: "Conditional Power" },
{ value: "583", label: "Slave Protagonist" }, { value: "584", label: "Mystery Solving" }, { value: "585", label: "Episodic" },
{ value: "586", label: "Fanaticism" }, { value: "587", label: "Omegaverse" }, { value: "588", label: "Priests" },
{ value: "589", label: "Stalkers" }, { value: "590", label: "Multiple Personalities" }, { value: "591", label: "Multiple Timelines" },
{ value: "592", label: "Crime" }, { value: "593", label: "Angels" }, { value: "594", label: "Awkward Protagonist" },
{ value: "595", label: "Destiny" }, { value: "596", label: "Disabilities" }, { value: "597", label: "Dragon Riders" },
{ value: "598", label: "Glasses-wearing Protagonist" }, { value: "599", label: "Helpful Protagonist" }, { value: "600", label: "Animal Characteristics" },
{ value: "601", label: "Shapeshifters" }, { value: "602", label: "Love Rivals" }, { value: "603", label: "Straight Seme" },
{ value: "604", label: "Straight Uke" }, { value: "605", label: "Chat Rooms" }, { value: "606", label: "Divination" },
{ value: "607", label: "Famous Parents" }, { value: "608", label: "Playboys" }, { value: "609", label: "Wars Weak to Strong" },
{ value: "610", label: "Cunnilingus" }, { value: "611", label: "Marriage of Convenience" }, { value: "612", label: "Police" },
{ value: "613", label: "Scheming" }, { value: "614", label: "Clones" }, { value: "615", label: "Heroes" },
{ value: "616", label: "Loli" }, { value: "617", label: "Reincarnated into Another World" }, { value: "618", label: "R-15" },
{ value: "619", label: "Butlers" }, { value: "620", label: "Reincarnated as a Monster" }, { value: "621", label: "Seven Virtues" },
{ value: "622", label: "Unreliable Narrator" }, { value: "623", label: "Witches" }, { value: "624", label: "Psychopaths" },
{ value: "625", label: "Neet" }, { value: "626", label: "S*x Friends" }, { value: "627", label: "Introverted Protagonist" },
{ value: "628", label: "Multiple Protagonists" }, { value: "629", label: "Non-linear Storytelling" }, { value: "630", label: "Resurrection" },
{ value: "631", label: "Folklore" }, { value: "632", label: "Puppeteers" }, { value: "633", label: "Romance" },
{ value: "634", label: "Modern" }, { value: "635", label: "Antagonist" }, { value: "636", label: "love" },
{ value: "637", label: "Drama" }, { value: "638", label: "Female Lead" }, { value: "639", label: "no-misunderstanding" },
{ value: "640", label: "contemporary romance" }, { value: "641", label: "backstabbing" }, { value: "642", label: "Complete" },
{ value: "643", label: "Child Protagonist" }, { value: "644", label: "Daoism" }, { value: "645", label: "S*aves" },
{ value: "646", label: "First-time Interc**rse" }, { value: "647", label: "Comedy" }, { value: "648", label: "Mature" },
{ value: "649", label: "Mystery" }, { value: "650", label: "Adapted to Manhwa" }, { value: "651", label: "Conspiracies" },
{ value: "652", label: "Bookworm" }, { value: "653", label: "Mysterious Illness" }, { value: "654", label: "Antique Shop" },
{ value: "655", label: "Indecisive Protagonist" }, { value: "656", label: "Seeing Things Other Humans Can't" }, { value: "657", label: "Doting male lead" },
{ value: "658", label: "Saints" }, { value: "659", label: "Female Master" }, { value: "660", label: "Adapted to Game" },
{ value: "661", label: "Monster Girls" }, { value: "662", label: "Adapted to Movie" }, { value: "663", label: "Eunuch" },
{ value: "664", label: "Otome Game" }, { value: "665", label: "Adapted to Visual Novel" }, { value: "666", label: "Evil MC" },
{ value: "667", label: "Shameless MC" }, { value: "668", label: "SwordAndMagic" }, { value: "669", label: "Debts" },
{ value: "670", label: "Valkyries" }, { value: "671", label: "Dishonest Protagonist" }, { value: "672", label: "Brainwashing" },
{ value: "673", label: "Curious Protagonist" }, { value: "674", label: "Prostit**es" }, { value: "675", label: "Blackmail" },
{ value: "676", label: "Criminals" }, { value: "677", label: "Disfigurement" }, { value: "678", label: "Male Lead" },
{ value: "679", label: "Historical" }, { value: "680", label: "Rivalry" }, { value: "681", label: "Earth Invasion" },
{ value: "682", label: "Divine Protection" }, { value: "683", label: "Exorcism" }, { value: "684", label: "Grave Keepers" },
{ value: "685", label: "Hell" }, { value: "686", label: "Animal Rearing" }, { value: "687", label: "Heaven" },
{ value: "688", label: "Adventure" }, { value: "689", label: "Sci-Fi" }, { value: "690", label: "Science Fiction" },
{ value: "691", label: "Mechs" }, { value: "692", label: "Mech Designer" }, { value: "693", label: "Space Opera" },
{ value: "694", label: "Starships" }, { value: "695", label: "RPG System" }, { value: "696", label: "Sudden Wealth" },
{ value: "697", label: "Tsundere Protagonist" }, { value: "698", label: "Priestesses" }, { value: "699", label: "Body Swap" },
{ value: "700", label: "ArrogantCharacters" }, { value: "701", label: "BeastCompanions" }, { value: "702", label: "CleverProtagonist" },
{ value: "703", label: "Spies" }, { value: "704", label: "Sculptors" }, { value: "705", label: "R*pe Victim Becomes Lover" },
{ value: "706", label: "Reverse R*pe" }, { value: "707", label: "F*llatio" }, { value: "708", label: "Parasites" },
{ value: "709", label: "R*pe" }, { value: "710", label: "Engagement" }, { value: "711", label: "Inferiority Complex" },
{ value: "712", label: "S*xual Abuse" }, { value: "713", label: "Human Weapon" }, { value: "714", label: "Ninjas" },
{ value: "715", label: "Emotionally Weak Protagonist" }, { value: "716", label: "Shota" }, { value: "717", label: "Shoujo-Ai Subplot" },
{ value: "718", label: "Dystopia" }, { value: "719", label: "Fat Protagonist" }, { value: "720", label: "Ugly Protagonist" },
{ value: "721", label: "An*l" }, { value: "722", label: "Mind Break" }, { value: "723", label: "Outdoor Interc**rse" },
{ value: "724", label: "Salaryman" }, { value: "725", label: "Sibling's Care" }, { value: "726", label: "Prison" },
{ value: "727", label: "Sadistic Characters" }, { value: "728", label: "Fat to Fit" }, { value: "729", label: "Dead Protagonist" },
{ value: "730", label: "Body-double" }, { value: "731", label: "Cohabitation" }, { value: "732", label: "Confinement" },
{ value: "733", label: "Conflicting Loyalties" }, { value: "734", label: "Social Outcasts" }, { value: "735", label: "Suicides" },
{ value: "736", label: "Schizophrenia" }, { value: "737", label: "FemaleProtagonist" }, { value: "738", label: "HandsomeMaleLead" },
{ value: "739", label: "PossessiveCharacters" }, { value: "740", label: "PowerCouple" }, { value: "741", label: "SlowRomance" },
{ value: "742", label: "Kind Love Interests" }, { value: "743", label: "Language Barrier" }, { value: "744", label: "Timid Protagonist" },
{ value: "745", label: "Anti-Magic" }, { value: "746", label: "Coming of Age" }, { value: "747", label: "Exhibitionism" },
{ value: "748", label: "Futanari" }, { value: "749", label: "Sleeping" }, { value: "750", label: "Spirit Users" },
{ value: "751", label: "Flashbacks" }, { value: "752", label: "Amusement Park" }, { value: "753", label: "Serial Killers" },
{ value: "754", label: "Former Hero" }, { value: "755", label: "Award-winning Work" }, { value: "756", label: "Child Abuse" },
{ value: "757", label: "Delinquents" }, { value: "758", label: "Entertainment" }, { value: "759", label: "Aggressive Characters" },
{ value: "760", label: "Anti-social Protagonist" }, { value: "761", label: "Court Official" }, { value: "762", label: "Loneliness" },
{ value: "763", label: "Toys" }, { value: "764", label: "Nightmares" }, { value: "765", label: "Androids" },
{ value: "766", label: "Future Civilization" }, { value: "767", label: "Childhood Sweethearts" }, { value: "768", label: "Villain" },
{ value: "769", label: "Character Development" }, { value: "770", label: "Quick Transmigration" }, { value: "771", label: "Dream" },
{ value: "772", label: "Pilots" }, { value: "773", label: "Male to Female" }, { value: "774", label: "Onmyouji" },
{ value: "775", label: "Shikigami" }, { value: "776", label: "Tomboyish Female Lead" }, { value: "777", label: "Female Master Friendship" },
{ value: "778", label: "Romantic Subplot Ruthless Protagonist" }, { value: "779", label: "Saint" }, { value: "780", label: "Rebellion" },
{ value: "781", label: "Netorare" }, { value: "782", label: "Distrustful Protagonist" }, { value: "783", label: "Voice Actors" },
{ value: "784", label: "Pretend Lovers" }, { value: "785", label: "Hospital" }, { value: "786", label: "Part-Time Job" },
{ value: "787", label: "Breast Fetish" }, { value: "788", label: "Co-Workers" }, { value: "789", label: "Office Romance" },
{ value: "790", label: "Gladiators" }, { value: "791", label: "Online Game" }, { value: "792", label: "Incubus" },
{ value: "793", label: "Divination Enlightenment" }, { value: "794", label: "eastern fantasy" }, { value: "795", label: "Knights Level System" },
{ value: "796", label: "Roommates" }, { value: "797", label: "Pacifist Protagonist" }, { value: "798", label: "Adapted from Manga" },
{ value: "799", label: "Coma" }, { value: "800", label: "Lolicon" }, { value: "801", label: "Matriarchy" },
{ value: "802", label: "Time Loop" }, { value: "803", label: "Dancers" }, { value: "804", label: "Feng Shui" },
{ value: "805", label: "Younger Brothers" }, { value: "806", label: "Special Abilitie" }, { value: "807", label: "Otaku" },
{ value: "808", label: "Samurai" }, { value: "809", label: "Crossover" }, { value: "810", label: "Youkai" },
{ value: "811", label: "Outcasts" }, { value: "812", label: "Xianxia" }, { value: "813", label: "Harem-seeking Protagonist Harsh Training" },
{ value: "814", label: "Fujoshi" }, { value: "815", label: "Waiters" }, { value: "816", label: "Short Story" },
{ value: "817", label: "Magical Girls" }, { value: "818", label: "Senpai-Kouhai Relationship" }, { value: "819", label: "Quiet Characters" },
{ value: "820", label: "Selfless Protagonist" }, { value: "821", label: "Imaginary Friend" }, { value: "822", label: "Mythical" },
{ value: "823", label: "War Records" }, { value: "824", label: "Artifacts Body Tempering" }, { value: "825", label: "One Piece" },
{ value: "826", label: "Apartment Life" }, { value: "827", label: "Based on a Song" }, { value: "828", label: "Vocaloid" },
{ value: "829", label: "Glasses-wearing Love Interests" }, { value: "830", label: "Reincarnated as an Object" }, { value: "831", label: "Long-distance Relationship" },
{ value: "832", label: "Cosplay" }, { value: "833", label: "Female to Male" }, { value: "834", label: "Mangaka" },
{ value: "835", label: "Misandry" }, { value: "836", label: "Harry Potter" }, { value: "837", label: "Jiangshi" },
{ value: "838", label: "No Harem" }, { value: "839", label: "Genius Female Lead" }, { value: "840", label: "Steamy" },
{ value: "841", label: "Smart female lead" }, { value: "842", label: "Hacker" }, { value: "843", label: "Forced Living Arrangements" },
{ value: "844", label: "Hentai" }, { value: "845", label: "NonHuman Protagonist" }, { value: "846", label: "Video-Game Elements" },
{ value: "847", label: "Dungeon" }, { value: "848", label: "Snow Girl" }, { value: "849", label: "Sentimental Protagonist" },
{ value: "850", label: "Identity Crisis" }, { value: "851", label: "Mismatched Couple" }, { value: "852", label: "Bisexual Protagonist" },
{ value: "853", label: "Rich to Poor" }, { value: "854", label: "Reluctant Protagonist" }, { value: "855", label: "Tentacles" },
{ value: "856", label: "Homunculus" }, { value: "857", label: "Mute Character" }, { value: "858", label: "Sharing A Body" },
{ value: "859", label: "Netorase" }, { value: "860", label: "Wishes" }, { value: "861", label: "Overpowered" },
{ value: "862", label: "Original" }, { value: "863", label: "Cute" }, { value: "864", label: "Desperate" },
{ value: "865", label: "Multiple Bodies" }, { value: "866", label: "Shield User" }, { value: "867", label: "spirit realm" },
{ value: "868", label: "All-Girls School" }, { value: "869", label: "Galge" }, { value: "870", label: "Forgetful Protagonist" },
{ value: "871", label: "Reversible Couple" }, { value: "872", label: "Bands" }, { value: "873", label: "LitRPG" },
{ value: "874", label: "Hikikomori" }, { value: "875", label: "Jobless Class" }, { value: "876", label: "Sign Language" },
{ value: "877", label: "Artifacts Cultivation" }, { value: "878", label: "Nurses" }, { value: "879", label: "Pill Concoting" },
{ value: "880", label: "Monster Catching" }, { value: "881", label: "Gaming/E-Sport" }, { value: "882", label: "Based on a Movie" },
{ value: "883", label: "Marvel" }, { value: "884", label: "Marvel Universe" }, { value: "885", label: "War" },
{ value: "886", label: "Smart mc" }, { value: "887", label: "Multiverse" }, { value: "888", label: "Shotacon" },
{ value: "889", label: "Yaoi" }, { value: "890", label: "Bestiality" }, { value: "891", label: "face slapping" },
{ value: "892", label: "Non-human Protagonist" }, { value: "893", label: "Delusions" }, { value: "894", label: "Based on an Anime" },
{ value: "895", label: "Oneshot" }, { value: "896", label: "Political Intrigue" }, { value: "897", label: "Reporters" },
{ value: "898", label: "Astrologers" }, { value: "899", label: "Unlimited Flow" }, { value: "900", label: "Martialarts" },
{ value: "901", label: "Hokage" }, { value: "902", label: "Kakashi" }, { value: "903", label: "Talent Prophecies" },
{ value: "904", label: "Sign-in" }, { value: "905", label: "Pokemon" }, { value: "906", label: "School Life" },
{ value: "907", label: "Decisive Mc" }, { value: "908", label: "Knight" }, { value: "909", label: "Mystical" },
{ value: "910", label: "OP MC" }, { value: "911", label: "Orgy" }, { value: "912", label: "Slave" },
{ value: "913", label: "Game" }, { value: "914", label: "Non-Human MC" }, { value: "915", label: "Undead" },
{ value: "916", label: "Warcraft" }, { value: "917", label: "Over-Powered Protagonist" }, { value: "918", label: "Europe" },
{ value: "919", label: "Basketball" }, { value: "920", label: "Dynasty" }, { value: "921", label: "travel" },
{ value: "922", label: "Rebirthed Protagonist" }, { value: "923", label: "Sign-In/Check-In" }, { value: "924", label: "Super Technology" },
{ value: "925", label: "long lived main character" }, { value: "926", label: "Pampering Romance" }, { value: "927", label: "Murder" },
{ value: "928", label: "Phobias" }, { value: "929", label: "Demons Familiars" }, { value: "930", label: "Based on a TV Show" },
{ value: "931", label: "Adult" }, { value: "932", label: "Anti-MC" }, { value: "933", label: "Douluo" },
{ value: "934", label: "Crossing" }, { value: "935", label: "Fight for hegemony" }, { value: "936", label: "Operation" },
{ value: "937", label: "Formation" }, { value: "938", label: "Luck" }, { value: "939", label: "Male Protaganist" },
{ value: "940", label: "WW2" }, { value: "941", label: "Civilization" }, { value: "942", label: "Creation" },
{ value: "943", label: "Epic Fantasy" }, { value: "944", label: "Voyeurism" }, { value: "945", label: "Isekai" },
{ value: "946", label: "Multiple CP" }, { value: "947", label: "Danmei" }, { value: "948", label: "Livestreaming" },
{ value: "949", label: "Found Family" }, { value: "950", label: "Living Abroad" }, { value: "951", label: "Ancient ChinaFanfiction" },
{ value: "952", label: "Entertainment Industry" }, { value: "953", label: "Blind Dates" }, { value: "954", label: "Guideverse" },
{ value: "955", label: "Based on a Video Game" }, { value: "956", label: "Invisibility" }, { value: "957", label: "Biotechnology" },
{ value: "958", label: "Interstellar" }, { value: "959", label: "No Cp" }, { value: "960", label: "Science" },
{ value: "961", label: "Technology" }, { value: "962", label: "Transmigrate" }, { value: "963", label: "Uplifting Civilization" },
{ value: "964", label: "Zerg" }, { value: "965", label: "Titans" }, { value: "966", label: "Classic" },
{ value: "967", label: "Soccer" }, { value: "968", label: "Eastern Setting" }, { value: "969", label: "Gamer" },
{ value: "970", label: "Beautiful Couple" }, { value: "971", label: "Modern Fantasy" }, { value: "972", label: "Sex Friends" },
{ value: "973", label: "Akame Ga Kill" }, { value: "974", label: "My Hero Academia" }, { value: "975", label: "X-men" },
{ value: "976", label: "DC Universe" }, { value: "977", label: "Super Heroes" }, { value: "978", label: "Rank System" },
{ value: "979", label: "Solo Leveling" }, { value: "980", label: "Portal Fantasy" }, { value: "981", label: "Progression" },
{ value: "982", label: "High Fantasy" }, { value: "983", label: "Grimdark" }, { value: "984", label: "Avatar: The Last Airbender" },
{ value: "985", label: "Protagonist Loyal to Love Interest" }, { value: "986", label: "Not Harem" }, { value: "987", label: "No Cheats" },
{ value: "988", label: "Highschool of the Dead" }, { value: "989", label: "Protagonist NPC" }, { value: "990", label: "Mistaken Identity" },
{ value: "991", label: "Dragon" }, { value: "992", label: "High School DxD" }, { value: "993", label: "Charlotte (anime)" },
{ value: "994", label: "Ruling Class" }, { value: "995", label: "Strong Lead" }, { value: "996", label: "Slow Cultivation" },
{ value: "997", label: "Webnovel Spirity Awards" }, { value: "998", label: "Kanojo Okarishimasu" }, { value: "999", label: "My Wife Is A Beautiful CEO" },
{ value: "1000", label: "Return of the Dragon King" }, { value: "1001", label: "Shinmai Mao no Tastement" }, { value: "1002", label: "Highschool DxD" },
{ value: "1003", label: "Bleach" }, { value: "1004", label: "Hunter X Hunter" }, { value: "1005", label: "Attack on Titan" },
{ value: "1006", label: "Devils" }, { value: "1007", label: "Fairy Tail" }, { value: "1008", label: "College or University" },
{ value: "1009", label: "Sects" }, { value: "1010", label: "Not Netorare" }, { value: "1011", label: "Jujutsu Kaisen" },
{ value: "1012", label: "Noble" }, { value: "1013", label: "No Romance" }, { value: "1014", label: "Strategy" },
{ value: "1015", label: "Psychological" }, { value: "1016", label: "Tokyo Ghoul" }, { value: "1017", label: "Minecraft" },
{ value: "1018", label: "Gintama" }, { value: "1019", label: "Dolls or Puppets" }, { value: "1020", label: "Fate/Grand Order" },
{ value: "1021", label: "Campione!" }, { value: "1022", label: "Skyrim" }, { value: "1023", label: "RWBY" },
{ value: "1024", label: "Cyberpunk" }, { value: "1025", label: "Modern Time" }, { value: "1026", label: "Type-Moon" },
{ value: "1027", label: "One-Punch Man" }, { value: "1028", label: "Satire" }, { value: "1029", label: "Food Shopkeeper" },
{ value: "1030", label: "Lord of Mysteries" }, { value: "1031", label: "Doulou Dalu" }, { value: "1032", label: "CEO" },
{ value: "1033", label: "Not Yaoi" }, { value: "1034", label: "Gothic" }, { value: "1035", label: "Kenichi: The Mightiest Disciple" },
{ value: "1036", label: "Enemies" }, { value: "1037", label: "Steampunk" }, { value: "1038", label: "Low Fantasy" },
{ value: "1039", label: "Crazy Protagonist" }, { value: "1040", label: "RPG" }, { value: "1041", label: "Resolute Protagonist" },
{ value: "1042", label: "Record of Ragnarok" }, { value: "1043", label: "Space" }, { value: "1044", label: "Amorality Protagonist" },
{ value: "1045", label: "Battle Through the Heavens" }, { value: "1046", label: "Apocalyptic" }, { value: "1047", label: "Soft Sci-fi" },
{ value: "1048", label: "Karma" }, { value: "1049", label: "Diplomacy" }, { value: "1050", label: "Gender Bender" },
{ value: "1051", label: "Sports" }, { value: "1052", label: "World Invasion" }, { value: "1053", label: "Vampire" },
{ value: "1054", label: "Game Element" }, { value: "1055", label: "Angst" }, { value: "1056", label: "The Asterisk War" },
{ value: "1057", label: "sciencefiction" }, { value: "1058", label: "Game of Thrones" }, { value: "1059", label: "ASOIAF" },
{ value: "1060", label: "Mythos" }, { value: "1061", label: "Spec" }, { value: "1062", label: "Smut" },
{ value: "1063", label: "Hiding Identity" }, { value: "1064", label: "Goddess" }, { value: "1065", label: "Urban Fantasy" },
{ value: "1066", label: "Warcaft" }, { value: "1067", label: "Little Romance" }, { value: "1068", label: "Overlord" },
{ value: "1069", label: "Genshin Impact" }, { value: "1070", label: "Girl's Love Subplot" }, { value: "1071", label: "Dwarves" },
{ value: "1072", label: "Warhammer" }, { value: "1073", label: "The Gamer" }, { value: "1074", label: "Rich Protagonist" },
{ value: "1075", label: "LGBTQA" }, { value: "1076", label: "Chatgroup" }, { value: "1077", label: "Week to Strong" },
{ value: "1078", label: "GameLit" }, { value: "1079", label: "Warhammer 40K" }, { value: "1080", label: "Healing" },
{ value: "1081", label: "Godzilla" }, { value: "1082", label: "Dark Souls" }, { value: "1083", label: "Subtle Romance" },
{ value: "1084", label: "Mage" }, { value: "1085", label: "Resident Evil" }, { value: "1086", label: "supernatural" },
{ value: "1087", label: "Tales of Demons and Gods" }, { value: "1088", label: "SCP" }, { value: "1089", label: "Not Netori" },
{ value: "1090", label: "Star Wars" }, { value: "1091", label: "Multiple Lead Characters" }, { value: "1092", label: "Adapted from Manhua" },
{ value: "1093", label: "Trolls" }, { value: "1094", label: "Fallout: New Vegas" }, { value: "1095", label: "Sci-Fantasy" },
{ value: "1096", label: "Planets" }, { value: "1097", label: "Evil Organization" }, { value: "1098", label: "Secret Organization" },
{ value: "1099", label: "Detective Conan" }, { value: "1100", label: "Non-Human lead" }, { value: "1101", label: "DanMachi" },
{ value: "1102", label: "Alchemist" }, { value: "1103", label: "From the first POV" }, { value: "1104", label: "Fourth Wall" },
{ value: "1105", label: "Reader Interactive" }, { value: "1106", label: "DEVIL" }, { value: "1107", label: "Fate/stay night" },
{ value: "1108", label: "Hollywood" }, { value: "1109", label: "Fallout" }, { value: "1110", label: "R18" },
{ value: "1111", label: "Weaktostrong" }, { value: "1112", label: "Myth" }, { value: "1113", label: "Antihero" },
{ value: "1114", label: "Blodpumping" }, { value: "1115", label: "Culinary" }, { value: "1116", label: "Food" },
{ value: "1117", label: "gourmet" }, { value: "1118", label: "Mysterious Organization" }, { value: "1119", label: "Scary" },
{ value: "1120", label: "The Truth" }, { value: "1121", label: "Decryption" }, { value: "1122", label: "China's Qinling Mountains" },
{ value: "1123", label: "The Desert" }, { value: "1124", label: "Stimulus" }, { value: "1125", label: "Terrori" },
{ value: "1126", label: "UFO" }, { value: "1127", label: "The Aliens" }, { value: "1128", label: "The Prehistoric Civilization" },
{ value: "1129", label: "Parallel Universe" }, { value: "1130", label: "Quantum Mechanics" }, { value: "1131", label: "Multidimensional Space" },
{ value: "1132", label: "Semiotics" }, { value: "1133", label: "Secretive" }, { value: "1134", label: "Super Ability" },
{ value: "1135", label: "A Dead Body" }, { value: "1136", label: "Evil Spirit Ghost" }, { value: "1137", label: "Catch a Ghost" },
{ value: "1138", label: "Popular" }, { value: "1139", label: "Pretty Girl" }, { value: "1140", label: "The Main Character Charm" },
{ value: "1141", label: "The Devil" }, { value: "1142", label: "Businesswoman" }, { value: "1143", label: "Secret Love" },
{ value: "1144", label: "Excellent Skills" }, { value: "1145", label: "A Psychic Detective" }, { value: "1146", label: "Ghost Event" },
{ value: "1147", label: "The Paranormal" }, { value: "1148", label: "Beasttaming" }, { value: "1149", label: "Slice of Life" },
{ value: "1150", label: "Faceslapping" }, { value: "1151", label: "Genus" }, { value: "1152", label: "Levelup" },
{ value: "1153", label: "Highiq" }, { value: "1154", label: "First Contact" }, { value: "1155", label: "Hard sci-fi" },
{ value: "1156", label: "Collection of short stories" }, { value: "1157", label: "Infinite flow" }, { value: "1158", label: "Races" },
{ value: "1159", label: "Attractive Lead" }, { value: "1160", label: "Egoist Protagonist" }, { value: "1161", label: "Genius" },
{ value: "1162", label: "Videogame" }, { value: "1163", label: "Tragedy" }, { value: "1164", label: "Percy jackson" },
{ value: "1165", label: "Kingdombuilding" }, { value: "1166", label: "Conquer" }, { value: "1167", label: "Sliceoflife" },
{ value: "1168", label: "Killer" }, { value: "1169", label: "Advancedtechnology" }, { value: "1170", label: "Dc" },
{ value: "1171", label: "Yuri" }, { value: "1172", label: "Possessive" }, { value: "1173", label: "Fastpaced" },
{ value: "1174", label: "Warm" }, { value: "1175", label: "Adapted Manhwa" }, { value: "1176", label: "Sports Basketball" },
{ value: "1177", label: "Tree Protagonist" }, { value: "1178", label: "World treeAdapted to Manhua" }, { value: "1179", label: "system owner" },
{ value: "1180", label: "Superheroes" }, { value: "1181", label: "Pansexual protagonist" }, { value: "1182", label: "Reincarnated into a game world" },
{ value: "1183", label: "Cheating" }, { value: "1184", label: "Special forces" }, { value: "1185", label: "Transgender" },
{ value: "1186", label: "Onepiece" }, { value: "1187", label: "Anime" }, { value: "1188", label: "Immortal" },
{ value: "1189", label: "Vampire diaries" }, { value: "1190", label: "Demon slayer" }, { value: "1191", label: "Avatar" },
{ value: "1192", label: "Full Metal Alchemist" }, { value: "1193", label: "Dragon Ball" }, { value: "1194", label: "Powerfulcouple" },
{ value: "1195", label: "Thestrongactingweak" }, { value: "1196", label: "Ecchi" }, { value: "1197", label: "Fate" },
{ value: "1198", label: "Fate stay night" }, { value: "1199", label: "Unprincipled" }, { value: "1200", label: "Egoist" },
{ value: "1201", label: "Beast taming" }, { value: "1202", label: "Angel" }, { value: "1203", label: "Positive" },
{ value: "1204", label: "Yu-gi-oh" }, { value: "1205", label: "Nonhuman" }, { value: "1206", label: "Black clover" },
{ value: "1207", label: "Summons" }, { value: "1208", label: "Bloodpumping" }, { value: "1209", label: "Simulation" },
{ value: "1210", label: "PUBG" }, { value: "1211", label: "Call of Cthulhu" }, { value: "1212", label: "Urban Life" },
{ value: "1213", label: "Star Trek" }, { value: "1214", label: "The Wizard of Oz" }, { value: "1215", label: "Maleficent" },
{ value: "1216", label: "Sleeping Beauty" }, { value: "1217", label: "Aladdin" }, { value: "1218", label: "Addpoint" },
{ value: "1219", label: "Cheat" }, { value: "1220", label: "Suivivalgame" }, { value: "1221", label: "VoyeurismAbsent Parents" },
{ value: "1222", label: "Human-nonhuman relationshipAdapted to Manhua" }, { value: "1223", label: "Forced living arrangementsApocalypse" }, { value: "1224", label: "Npc" },
{ value: "1225", label: "Wild peopleAntihero Protagonist" }, { value: "1226", label: "Transported into a game worldAcademy" }, { value: "1227", label: "LivestreamingFemale Protagonist" },
{ value: "1228", label: "Hidden abilitiesCultivation" }, { value: "1229", label: "Seeing things other humans can'tCalm Protagonist" }, { value: "1230", label: "Vtuber" },
{ value: "1231", label: "Dark themes" }, { value: "1232", label: "Curious protagonistAntihero Protagonist" }, { value: "1233", label: "Villainess noble girlsAdapted to Manhwa" },
{ value: "1234", label: "Awakening" }, { value: "1235", label: "ThrillerAdapted to Manhwa" }, { value: "1236", label: "Josei" },
{ value: "1237", label: "Female protagonistAbsent Parents" }, { value: "1238", label: "Strong female leadAdapted to Manhwa" }, { value: "1239", label: "Marriage of convenienceComedic Undertone" },
{ value: "1240", label: "Dragon slayersAcademy" }, { value: "1241", label: "InsectsAdapted to Manhwa" }, { value: "1242", label: "WitchesAcademy" },
{ value: "1243", label: "Child growth" }, { value: "1244", label: "Family drama" }, { value: "1245", label: "Cute female lead" },
{ value: "1246", label: "Strong female leadAdopted Protagonist" }, { value: "1247", label: "Carefree protagonistCarefree Protagonist" }, { value: "1248", label: "Transported into a game worldAristocracy" },
{ value: "1249", label: "Hot-blooded protagonistBeautiful Female Lead" }, { value: "1250", label: "Immortal cultivation" }, { value: "1251", label: "Hot-blooded protagonistArmy Building" },
{ value: "1252", label: "Determined protagoni" }, { value: "1253", label: "Demonic cultivation techniqueAccelerated Growth" }, { value: "1254", label: "WitchesAntihero Protagonist" },
{ value: "1255", label: "R-15Absent Parents" }, { value: "1256", label: "Shounen ai" }, { value: "1257", label: "SleepingAbandoned Children" },
{ value: "1258", label: "Adapted to drama cdAdapted to Drama CD" }, { value: "1259", label: "Single parentActing" }, { value: "1260", label: "Reincarnated in a game worldAbandoned Children" },
{ value: "1261", label: "Half-human protagonistAbility Steal" }, { value: "1262", label: "Beautiful female leadAlternate World" }, { value: "1263", label: "Reborn" },
{ value: "1264", label: "Absent parentsAntihero Protagonist" }, { value: "1265", label: "Time paradoxAdapted to Drama CD" }, { value: "1266", label: "PriestessesAdapted to Manhua" },
{ value: "1267", label: "Pro gamer" }, { value: "1268", label: "Virtual world" }, { value: "1269", label: "Online gaming" },
{ value: "1270", label: "Non-protagonist pov" }, { value: "1271", label: "Transformation" }, { value: "1272", label: "Psychological struggle" },
{ value: "1273", label: "Envy" }, { value: "1274", label: "Esports" }, { value: "1275", label: "Streamer" },
{ value: "1276", label: "Time loopAcademy" }, { value: "1277", label: "WitchesAbusive Characters" }, { value: "1278", label: "Inferiority complexAbsent Parents" },
{ value: "1279", label: "WishesCalm Protagonist" }, { value: "1280", label: "SuicidesAdapted to Drama CD" }, { value: "1281", label: "LawyersAcademy" },
{ value: "1282", label: "Lack of common senseAdventurers" }, { value: "1283", label: "Cold love interestsCo-Workers" }, { value: "1284", label: "Forgetful protagonistArrogant Characters" },
{ value: "1285", label: "Hiding true abilitiesAcademy" }, { value: "1286", label: "Fleet battlesAristocracy" }, { value: "1287", label: "Dragon hunting" },
{ value: "1288", label: "Strong female leadArranged Marriage" }, { value: "1289", label: "Protagonist falls in love firstBoss-Subordinate Relationship" }, { value: "1290", label: "Female protagonistFemale Protagonist" },
{ value: "1291", label: "Doting older siblingsAverage-looking Protagonist" }, { value: "1292", label: "SiblingsAmnesia" }, { value: "1293", label: "DystopiaAcademy" },
{ value: "1294", label: "Modern romance" }, { value: "1295", label: "Hero party" }, { value: "1296", label: "Early romanceArrogant Characters" },
{ value: "1297", label: "Complex family relationshipsAbusive Characters" }, { value: "1298", label: "Time paradoxAdopted Protagonist" }, { value: "1299", label: "Transported into a game worldAward-winning Work" },
{ value: "1300", label: "Determined protagonistCharacter Growth" }, { value: "1301", label: "Beautiful female leadBeautiful Female Lead" }, { value: "1302", label: "Scholar's life" },
{ value: "1303", label: "Seme protagonistAncient China" }, { value: "1304", label: "Possessive character" }, { value: "1305", label: "OrphansAbandoned Children" },
{ value: "1306", label: "Easy going lifeAncient China" }, { value: "1307", label: "Beautiful female lea" }, { value: "1308", label: "Manipulative charact" },
{ value: "1309", label: "Sword and magicAristocracy" }, { value: "1310", label: "Slow growth at startAccelerated Growth" }, { value: "1311", label: "Villainess noble gir" },
{ value: "1312", label: "Political dramaAristocracy" }, { value: "1313", label: "Lack of common senseAcademy" }, { value: "1314", label: "Ancient chinaAncient China" },
{ value: "1315", label: "Alternative history" }, { value: "1316", label: "Quick romance" }, { value: "1317", label: "Reverse domination" },
{ value: "1318", label: "Woman domination" }, { value: "1319", label: "Alternative world" }, { value: "1320", label: "Female dominant" },
{ value: "1321", label: "Prince" }, { value: "1322", label: "Black belly gongChildcare" }, { value: "1323", label: "Reverse haremBetrayal" },
{ value: "1324", label: "CursesAbandoned Children" }, { value: "1325", label: "Beautiful female leadAncient China" }, { value: "1326", label: "Carefree protagonistAngels" },
{ value: "1327", label: "Terminal illnessAncient Times" }, { value: "1328", label: "Parenting" }, { value: "1329", label: "CursesCurses" },
{ value: "1330", label: "Adapted to manhwaAdapted to Manhwa" }, { value: "1331", label: "Overprotective siblingsAbandoned Children" }, { value: "1332", label: "Childhood promiseAristocracy" },
{ value: "1333", label: "SpiesAdapted to Drama CD" }, { value: "1334", label: "ArmyAncient China" }, { value: "1335", label: "Shounen-ai subplotAcademy" },
{ value: "1336", label: "Regression" }, { value: "1337", label: "Hidden ability" }, { value: "1338", label: "Human x human relationship" },
{ value: "1339", label: "Imperial haremAncient China" }, { value: "1340", label: "Modern fantasyBrotherhood" }, { value: "1341", label: "Villainess noble girlsAdapted to Drama" },
{ value: "1342", label: "Determined protagonistAcademy" }, { value: "1343", label: "Fox girl" }, { value: "1344", label: "Human x non-human relationshipAnti-social Protagonist" },
{ value: "1345", label: "Returning from another worldActing" }, { value: "1346", label: "Mistaken identityBlind Dates" }, { value: "1347", label: "Devoted love interes" },
{ value: "1348", label: "Love interest falls" }, { value: "1349", label: "Wealthy charactersArtists" }, { value: "1350", label: "ComaAdapted to Manhwa" },
{ value: "1351", label: "Pretend loversArranged Marriage" }, { value: "1352", label: "Cd" }, { value: "1353", label: "Villainess noble girlsMaids" },
{ value: "1354", label: "Early romanceAbandoned Children" }, { value: "1355", label: "WerebeastsAge Regression" }, { value: "1356", label: "AffairAffair" },
{ value: "1357", label: "World hoppingCheats" }, { value: "1358", label: "Abandoned childrenAbandoned Children" }, { value: "1359", label: "Transported modern structureAndroids" },
{ value: "1360", label: "Non-humanoid protagonistAristocracy" }, { value: "1361", label: "Shield userAcademy" }, { value: "1362", label: "StalkersAdventurers" },
{ value: "1363", label: "Returning from another worldAcademy" }, { value: "1364", label: "Determined protagonistBusiness Management" }, { value: "1365", label: "Determined protagonistAristocracy" },
{ value: "1366", label: "Overpowered protagonistBetrayal" }, { value: "1367", label: "Proactive protagonistComedic Undertone" }, { value: "1368", label: "Past plays a big roleActing" },
{ value: "1369", label: "LivestreamingAlternate World" }, { value: "1370", label: "Beautiful female leadActing" }, { value: "1371", label: "Previous life talentArtists" },
{ value: "1372", label: "TeachersAdapted to Drama CD" }, { value: "1373", label: "Spirit usersAdventurers" }, { value: "1374", label: "InvisibilityAlternate World" },
{ value: "1375", label: "Returning from another worldAdapted to Manhwa" }, { value: "1376", label: "BeastkinAcademy" }, { value: "1377", label: "Reincarnated in another worldConfident Protagonist" },
{ value: "1378", label: "AdventurersAncient China" }, { value: "1379", label: "Emotionally weak protagonistAdventurers" }, { value: "1380", label: "Transported to another worldAbility Steal" },
{ value: "1381", label: "Martial artsAncient Times" }, { value: "1382", label: "Sect developmentMale Protagonist" }, { value: "1383", label: "Prodigy protagonist" },
{ value: "1384", label: "Innovative cultivation techniquesAdopted Protagonist" }, { value: "1385", label: "Shoujo-ai subplotAll-Girls School" }, { value: "1386", label: "RegressionHunters" },
{ value: "1387", label: "Emotionally weak protagonistAcademy" }, { value: "1388", label: "Powerful protagonist" }, { value: "1389", label: "MisunderstandingsArtifacts" },
{ value: "1390", label: "Adapted to manhwaAbility Steal" }, { value: "1391", label: "MunchkinAbility Steal" }, { value: "1392", label: "Politic" },
{ value: "1393", label: "Shounen aiModern Day" }, { value: "1394", label: "StrategistAdapted to Drama" }, { value: "1395", label: "Reincarnated as a monsterAncient Times" },
{ value: "1396", label: "Human-nonhuman relationshipAccelerated Growth" }, { value: "1397", label: "Weak protagonistBeautiful Female Lead" }, { value: "1398", label: "HuntersAcademy" },
{ value: "1399", label: "Fantasy worldCheats" }, { value: "1400", label: "Martial artsCultivation" }, { value: "1401", label: "Adoptedson" },
{ value: "1402", label: "Hunter" }, { value: "1403", label: "RegressionAcademy" }, { value: "1404", label: "Hiding true abilitiesDemon Lord" },
{ value: "1405", label: "Carefree protagonistAdapted to Manga" }, { value: "1406", label: "HypnosisAcademy" }, { value: "1407", label: "FairiesCheats" },
{ value: "1408", label: "Cute childrenCunning Protagonist" }, { value: "1409", label: "HuntersAlternate World" }, { value: "1410", label: "SingersCelebrities" },
{ value: "1411", label: "Complex family relationshipsAbsent Parents" }, { value: "1412", label: "CelebritiesActing" }, { value: "1413", label: "MerchantsBusiness Management" },
{ value: "1414", label: "Soul powerAccelerated Growth" }, { value: "1415", label: "R-15Adapted to Anime" }, { value: "1416", label: "Confident protagonis" },
{ value: "1417", label: "Strong love interestsAdapted to Anime" }, { value: "1418", label: "Reversible coupleAdapted to Anime" }, { value: "1419", label: "TeamworkAbsent Parents" },
{ value: "1420", label: "Sickly charactersAdapted to Drama CD" }, { value: "1421", label: "Witchcraft" }, { value: "1422", label: "Multiple love interests" },
{ value: "1423", label: "Beautiful female leads" }, { value: "1424", label: "Refiner" }, { value: "1425", label: "Souls merge" },
{ value: "1426", label: "Boy's Love Subplot" }, { value: "1427", label: "Historical fantasy" }, { value: "1428", label: "Myths" },
{ value: "1429", label: "Cold and calculating mc" }, { value: "1430", label: "Forbidden techniques" }, { value: "1431", label: "Overpowered main character" },
{ value: "1432", label: "Villain mc" }, { value: "1433", label: "Op" }, { value: "1434", label: "Side character" },
{ value: "1435", label: "Multiple destined ones" }, { value: "1436", label: "Bloodlnes" }, { value: "1437", label: "Overpowered system" },
{ value: "1438", label: "Assassin protagonist" }, { value: "1439", label: "Secret societies" }, { value: "1440", label: "Revenge & vendetta" },
{ value: "1441", label: "Twisted alliances" }, { value: "1442", label: "Bestkin" }, { value: "1443", label: "MagesBattle Academy" },
{ value: "1444", label: "Strong love interest" }, { value: "1445", label: "Mysterious family" }, { value: "1446", label: "Myrids worlds" },
{ value: "1447", label: "Portals" }, { value: "1448", label: "Forbidden love" }, { value: "1449", label: "Student-teacher romance" },
{ value: "1450", label: "Slow burn" }, { value: "1451", label: "Emotional angst" }, { value: "1452", label: "Obsession & desire" },
{ value: "1453", label: "Dream world" }, { value: "1454", label: "Overpowered mc" }, { value: "1455", label: "Physical refinement" },
{ value: "1456", label: "Mechas" }, { value: "1457", label: "Mystical powers" }, { value: "1458", label: "In love with the boss" },
{ value: "1459", label: "forbidden romance" }, { value: "1460", label: "Adventurer" }, { value: "1461", label: "Fantasy creaturesAdapted to Manhua" },
{ value: "1462", label: "Weak to strongCultivation" }, { value: "1463", label: "Power struggleMale Protagonist" }, { value: "1464", label: "Secret" },
{ value: "1465", label: "Relationsh" }, { value: "1466", label: "Prisons" }, { value: "1467", label: "Average" },
{ value: "1468", label: "Devoted love" }, { value: "1469", label: "Artifacts refiner" }, { value: "1470", label: "DungeonsAlchemy" },
{ value: "1471", label: "AssassinsAssassins" }, { value: "1472", label: "Sentient objectsBeasts" }, { value: "1473", label: "Power struggleBattle Academy" },
{ value: "1474", label: "Hansome male lead" }, { value: "1475", label: "Type-moonFanfiction" }, { value: "1476", label: "Soul cultivation" },
{ value: "1477", label: "Reincanation" }, { value: "1478", label: "Eastern" }, { value: "1479", label: "Royalfamily" },
{ value: "1480", label: "Fatedlove" }, { value: "1481", label: "Werewolf" }, { value: "1482", label: "Alpha" },
{ value: "1483", label: "Princess" }, { value: "1484", label: "Seductive" }, { value: "1485", label: "Abusedfl" },
{ value: "1486", label: "Arrangedmarriage" }, { value: "1487", label: "Campus" }, { value: "1488", label: "Cosmic entities" },
{ value: "1489", label: "Indifferent hero" }, { value: "1490", label: "Anti-hero protagonist" }, { value: "1491", label: "Tribulations" },
{ value: "1492", label: "Body cultivation" }, { value: "1493", label: "Trasported into a game world" }, { value: "1494", label: "Temporal anomaly" },
{ value: "1495", label: "Quantum resonance" }, { value: "1496", label: "Chrono singularity" }, { value: "1497", label: "Void beasts" },
{ value: "1498", label: "Fractured timeline" }, { value: "1499", label: "Echo technology" }, { value: "1500", label: "Temporal core" },
{ value: "1501", label: "Anomalous evolution" }, { value: "1502", label: "Reality containment" }, { value: "1503", label: "Conscious emergence" },
{ value: "1504", label: "Synthetic emotion" }, { value: "1505", label: "Reckless compassion" }, { value: "1506", label: "Hope persistence" },
{ value: "1507", label: "Silent reverence" }, { value: "1508", label: "Becoming human" }, { value: "1509", label: "Relational intimacy" },
{ value: "1510", label: "Sacred stillness" }, { value: "1511", label: "Identity disintegration" }, { value: "1512", label: "Existential memory" },
{ value: "1513", label: "Sovereign without a throne" }, { value: "1514", label: "Machine with a soul" }, { value: "1515", label: "Sacrifice & resurrection" },
{ value: "1516", label: "Blue sanctuary" }, { value: "1517", label: "Post-hierarchical society" }, { value: "1518", label: "Dystopian" },
{ value: "1519", label: "Assassin/hitman" }, { value: "1520", label: "Shapeshifting" }, { value: "1521", label: "Guilds & organizations" },
{ value: "1522", label: "Training & growth" }, { value: "1523", label: "Revenge & justice" }, { value: "1524", label: "Anti-heroine" },
{ value: "1525", label: "Hidden identity" }, { value: "1526", label: "Special bloodline/race" }, { value: "1527", label: "Legendary weapons" },
{ value: "1528", label: "Magic system & ranks" }, { value: "1529", label: "Stealth & illusions" }, { value: "1530", label: "Dark organizations" },
{ value: "1531", label: "Strongest" }, { value: "1532", label: "Demon king" }, { value: "1533", label: "Ruthless" },
{ value: "1534", label: "Cruel" }, { value: "1535", label: "Weird" }, { value: "1536", label: "Yin job" },
{ value: "1537", label: "Demon" }, { value: "1538", label: "Portal" }, { value: "1539", label: "Plottwist" },
{ value: "1540", label: "Masterpiece" }, { value: "1541", label: "Brahmyodha" }, { value: "1542", label: "The destroyer" },
{ value: "1543", label: "Based on a Visual Novel" }, { value: "1544", label: "Cold but kind protagonist" }, { value: "1545", label: "Family feud" },
{ value: "1546", label: "Ruthless enemies" }, { value: "1547", label: "Rise to power" }, { value: "1548", label: "Street smart" },
{ value: "1549", label: "Business genius" }, { value: "1550", label: "Strong male lead" }, { value: "1551", label: "Hidden heir" },
{ value: "1552", label: "Backstab" }, { value: "1553", label: "The divine scion" }, { value: "1554", label: "Donghua" },
{ value: "1555", label: "Funny" }, { value: "1556", label: "Sigma" }, { value: "1557", label: "Soul land" },
{ value: "1558", label: "Doulu dalu" }, { value: "1559", label: "Experiments" }, { value: "1560", label: "Business" },
{ value: "1561", label: "Political Systems" }, { value: "1562", label: "Abused Characters" }, { value: "1563", label: "Counter-Strike" },
{ value: "1564", label: "Anti-Hero Lead" }, { value: "1565", label: "Magic beast" }, { value: "1566", label: "Demon hunter" },
{ value: "1567", label: "Wizard" }, { value: "1568", label: "Witcher" }, { value: "1569", label: "Monster" },
{ value: "1570", label: "Other world" }, { value: "1571", label: "Redemption" }, { value: "1572", label: "Guns" },
{ value: "1573", label: "Editors" }, { value: "1574", label: "Technology Gap" }, { value: "1575", label: "Tutorial" },
{ value: "1576", label: "Frieren" }, { value: "1577", label: "Clans" }, { value: "1578", label: "Dieselpunk" },
{ value: "1579", label: "FriendshipMale Protagonist" }, { value: "1580", label: "Mecha" }, { value: "1581", label: "Scheming Protagonist" },
{ value: "1582", label: "The Witcher" }, { value: "1583", label: "Adaptable Protagonist" }, { value: "1584", label: "Ambitious Protagonist" },
{ value: "1585", label: "Devouring" }, { value: "1586", label: "Based on History" }, { value: "1587", label: "World Building" },
{ value: "1588", label: "Single Female Lead" }, { value: "1589", label: "Wrongly Accused" }, { value: "1590", label: "Magic Academy" },
{ value: "1591", label: "Legacies" }, { value: "1592", label: "Age" }, { value: "1593", label: "VampiresAdapted to Manhua" },
{ value: "1594", label: "Faith Dependent Deities" }, { value: "1595", label: "Gao Wu" }, { value: "1596", label: "Dark Fantasy" }
]
}
};
}
const res = await fetch(
`${this.baseUrl}/ajax/searchLive?inputContent=${encodeURIComponent(query)}`,
{ headers: { "accept": "application/json" } }
async search({ query, filters }) {
// ------------------------------
// Lógica de Selección de Modo
// ------------------------------
// Si hay FILTROS activos (distintos a los default), usamos búsqueda AVANZADA (HTML)
const hasFilters = filters && Object.keys(filters).length > 0 && (
filters.sort !== 'bookmark' ||
filters.status !== '-1' ||
filters.chapters !== '0' ||
(filters.genres && filters.genres.length > 0) ||
(filters.tags && filters.tags.length > 0)
);
if (hasFilters) {
return this.searchAdvanced(query, filters);
} else {
// Si es búsqueda simple por texto sin filtros especiales, usamos la API AJAX (Más rápida)
return this.searchSimple(query);
}
}
// --- Modo Simple (AJAX) ---
async searchSimple(query) {
const url = `${this.baseUrl}/ajax/searchLive?inputContent=${encodeURIComponent(query || "")}`;
const res = await fetch(url, { headers: { "accept": "application/json" } });
const data = await res.json();
if (!data.data) return [];
return data.data.map(item => ({
@@ -22,10 +667,94 @@ class NovelFire {
title: item.title,
image: `https://novelfire.net/${item.image}`,
rating: item.rank ?? null,
type: "book"
type: "book",
// Construir la URL completa es buena práctica
url: `${this.baseUrl}/book/${item.slug}`
}));
}
// --- Modo Avanzado (HTML Scraping) ---
async searchAdvanced(query, filters) {
const url = new URL(`${this.baseUrl}/search-adv`);
// Parámetros por defecto para emular la request "all"
// NovelFire usa array params como country_id[]=1&country_id[]=2...
// Aquí hardcodeamos los orígenes "todos" para que no filtre por país salvo que quieras
[1, 2, 3, 4].forEach(id => url.searchParams.append('country_id[]', id));
url.searchParams.set('ctgcon', 'and'); // Categorías AND
url.searchParams.set('tagcon', 'and'); // Tags AND
// --- Filtro de Géneros (Categories) ---
if (filters && filters.genres) {
// El frontend manda string separado por comas "10,12,15"
const genreIds = String(filters.genres).split(',');
genreIds.forEach(id => {
if(id.trim()) url.searchParams.append('categories[]', id.trim());
});
}
// --- Filtro de Etiquetas (Tags) ---
if (filters && filters.tags) {
const tagIds = String(filters.tags).split(',');
tagIds.forEach(id => {
if(id.trim()) url.searchParams.append('tags[]', id.trim());
});
}
// --- Filtros Simples ---
if (filters) {
if (filters.status) url.searchParams.set('status', filters.status);
if (filters.sort) url.searchParams.set('sort', filters.sort);
if (filters.chapters && filters.chapters !== '0') {
url.searchParams.set('totalchapter', filters.chapters);
}
if (filters.rating) {
// Asumo que si el usuario filtra por rating, quiere rating alto (min 4 o 5)
// Aquí podrías hacerlo más complejo si el filtro rating tuviera opciones
// url.searchParams.set('ratcon', 'min');
// url.searchParams.set('rating', filters.rating);
}
}
// --- Fetch HTML ---
// console.log("NovelFire Adv Search URL:", url.toString());
const res = await fetch(url.toString());
const html = await res.text();
const $ = this.cheerio.load(html);
const results = [];
$('.novel-item').each((_, el) => {
const $el = $(el);
const titleEl = $el.find('.novel-title a');
const title = titleEl.text().trim();
const href = titleEl.attr('href');
if (!href) return;
// Extraer slug del href "/book/slug"
const id = href.replace('/book/', '');
const img = $el.find('.novel-cover img').attr('data-src') ||
$el.find('.novel-cover img').attr('src');
const rating = $el.find('.info-rating').attr('data-rating');
results.push({
id: id,
title: title,
image: img ? (img.startsWith('http') ? img : `${this.baseUrl}${img}`) : "",
rating: rating ? Number(rating) : null,
type: "book",
url: `${this.baseUrl}${href}`
});
});
return results;
}
async getMetadata(id) {
const url = `https://novelfire.net/book/${id}`;
const html = await (await fetch(url)).text();
@@ -95,6 +824,7 @@ class NovelFire {
"columns[0][orderable]": "false",
"columns[1][data]": "created_at",
"columns[1][orderable]": "true",
"columns[1][orderable]": "true",
"order[0][column]": 1,
"order[0][dir]": "asc",
start: 0,

View File

@@ -1,143 +1,267 @@
class wattpad {
class Wattpad {
constructor() {
this.baseUrl = "https://wattpad.com";
this.baseUrl = "https://www.wattpad.com";
this.apiUrl = "https://www.wattpad.com/v4";
this.type = "book-board";
this.mediaType = "ln";
this.version = "1.0"
this.mediaType = "ln"; // Light Novel
this.version = "1.1";
}
async search(queryObj) {
const query = queryObj.query?.trim() || "";
getFilters() {
return {
sort: {
label: "Sort By (Only for Explore)",
type: "select",
options: [
{ value: "hot", label: "Hot (Trending)" },
{ value: "new", label: "New (Latest)" },
{ value: "paid", label: "Paid Stories" }
],
default: "hot"
},
updated: {
label: "Last Updated (Search Only)",
type: "select",
options: [
{ value: "", label: "Any time" },
{ value: "24", label: "Today" },
{ value: "168", label: "This Week" },
{ value: "720", label: "This Month" },
{ value: "8760", label: "This Year" }
],
default: ""
},
content: {
label: "Content Filters",
type: "multiselect",
options: [
{ value: "completed", label: "Completed stories only" },
{ value: "paid", label: "Paid stories only (Hide free)" },
{ value: "free", label: "Free stories only (Hide Paid)" },
{ value: "mature", label: "Include mature content" }
]
},
tags: {
label: "Tags (comma separated)",
type: "text",
placeholder: "e.g. romance, vampire, magic"
}
};
}
get headers() {
return {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.wattpad.com/"
};
}
async search({ query, page = 1, filters }) {
const limit = 15;
const offset = 0;
const offset = (page - 1) * limit;
const url =
`${this.baseUrl}/v4/search/stories?` +
`query=${encodeURIComponent(query)}` +
`&limit=${limit}&offset=${offset}&mature=false`;
// 1. Preparar la Query (Texto + Etiquetas)
let finalQuery = (query || "").trim();
if (filters?.tags) {
const tags = String(filters.tags).split(",");
tags.forEach(t => {
const tag = t.trim();
if (tag) {
// Wattpad requiere que los tags en la búsqueda lleven #
finalQuery += ` #${tag.replace(/^#/, '')}`;
}
});
}
finalQuery = finalQuery.trim();
const json = await fetch(url).then(r => r.json());
let url;
return json.stories.map(n => ({
id: n.id,
title: n.title,
image: n.cover,
sampleImageUrl: n.cover,
tags: n.tags,
type: "book"
// 2. DECISIÓN: ¿Búsqueda o Exploración?
if (finalQuery) {
// CASO A: HAY BÚSQUEDA (Texto o Tags) -> Usar API de Search
url = new URL(`${this.apiUrl}/search/stories/`);
url.searchParams.set("query", finalQuery);
// Filtros exclusivos de búsqueda
if (filters?.updated) {
url.searchParams.set("updateYoungerThan", filters.updated);
}
} else {
// CASO B: NO HAY BÚSQUEDA (Default) -> Usar API de Stories (Explorar)
// Esto cargará "Tendencias" o "Nuevos" cuando entres sin escribir nada.
url = new URL(`${this.apiUrl}/stories/`);
// Mapear el filtro 'sort' al parámetro 'filter' de la API
// Por defecto usamos 'hot' (Tendencias)
const filterVal = filters?.sort || "hot";
url.searchParams.set("filter", filterVal);
}
// 3. Filtros Comunes (Content)
let isMature = false;
if (filters?.content) {
const contentOpts = Array.isArray(filters.content)
? filters.content
: String(filters.content).split(',');
if (contentOpts.includes("completed")) url.searchParams.set("completed", "1");
if (contentOpts.includes("paid")) url.searchParams.set("paid", "1");
if (contentOpts.includes("free")) url.searchParams.set("paid", "0");
if (contentOpts.includes("mature")) isMature = true;
}
// Wattpad requiere mature=1 explícito para mostrar contenido adulto
url.searchParams.set("mature", isMature ? "1" : "0");
// 4. Parámetros Técnicos
url.searchParams.set("limit", limit.toString());
url.searchParams.set("offset", offset.toString());
// Solicitar campos específicos para obtener portadas, autor y estado
const fields = "stories(id,title,voteCount,readCount,commentCount,description,mature,completed,cover,url,numParts,isPaywalled,paidModel,length,language(id),user(name),lastPublishedPart(createDate),promoted,sponsor(name,avatar),tags),total,nextUrl";
url.searchParams.set("fields", fields);
try {
const res = await fetch(url.toString(), { headers: this.headers });
if (!res.ok) {
console.error(`Wattpad API Error: ${res.status}`);
return [];
}
const json = await res.json();
if (!json.stories) return [];
return json.stories.map(story => ({
id: story.id,
title: story.title,
image: story.cover,
type: "book",
// Datos extra para la UI
author: story.user?.name,
status: story.completed ? "Completed" : "Ongoing",
chapters: story.numParts,
rating: story.voteCount // Opcional: usar votos como rating
}));
} catch (e) {
console.error("Wattpad search failed:", e);
return [];
}
}
async getMetadata(id) {
const html = await fetch(`${this.baseUrl}/story/${id}`).then(r => r.text());
// Obtenemos metadatos básicos de la web para no depender solo de la API
const res = await fetch(`${this.baseUrl}/story/${id}`, { headers: this.headers });
const html = await res.text();
const $ = this.cheerio.load(html);
// Intentar extraer datos del script de hidratación (más fiable)
const script = $('script')
.map((_, el) => $(el).html())
.get()
.find(t => t?.includes('window.__remixContext'));
if (!script) return null;
if (script) {
const jsonText = script.match(/window\.__remixContext\s*=\s*({[\s\S]*?});/)?.[1];
if (!jsonText) return null;
let ctx;
if (jsonText) {
try {
ctx = JSON.parse(jsonText);
} catch {
return null;
}
const ctx = JSON.parse(jsonText);
const route = ctx?.state?.loaderData?.["routes/story.$storyid"];
const story = route?.story;
const meta = route?.meta;
if (!story) return null;
if (story) {
return {
id: story.id,
title: story.title,
format: "Novel",
score: story.voteCount ?? null,
score: story.voteCount ?? 0,
genres: story.tags || [],
status: story.completed ? "Completed" : "Ongoing",
published: story.createDate?.split("T")[0] || "???",
summary: story.description || meta?.description || "",
chapters: story.numParts || story.parts?.length || 1,
image: story.cover || meta?.image || "",
language: story.language?.name?.toLowerCase() || "unknown",
published: story.createDate ? story.createDate.split("T")[0] : "???",
summary: story.description || "",
chapters: story.numParts || 0,
image: story.cover || "",
author: story.user?.name || ""
};
}
} catch (e) {}
}
}
// Fallback clásico
const title = $('h1').first().text().trim();
const image = $('.story-cover img').attr('src');
const summary = $('.description').text().trim();
return {
id,
title: title || "Unknown",
format: "Novel",
image: image || "",
summary: summary || "",
chapters: 0
};
}
async findChapters(bookId) {
const html = await fetch(`${this.baseUrl}/story/${bookId}`).then(r => r.text());
const $ = this.cheerio.load(html);
const res = await fetch(`${this.baseUrl}/story/${bookId}`, { headers: this.headers });
const html = await res.text();
const script = $('script')
.map((_, el) => $(el).html())
.get()
.find(t => t?.includes('window.__remixContext'));
// Extraer estructura de capítulos del JSON
const match = html.match(/window\.__remixContext\s*=\s*({[\s\S]*?});/);
if (!match?.[1]) return [];
if (!script) return [];
const jsonText = script.match(/window\.__remixContext\s*=\s*({[\s\S]*?});/)?.[1];
if (!jsonText) return [];
let ctx;
try {
ctx = JSON.parse(jsonText);
const ctx = JSON.parse(match[1]);
const story = ctx?.state?.loaderData?.["routes/story.$storyid"]?.story;
if (!story?.parts) return [];
return story.parts.map((part, i) => ({
id: String(part.id),
title: part.title || `Chapter ${i + 1}`,
number: i + 1,
index: i,
url: part.url
}));
} catch {
return [];
}
const story = ctx?.state?.loaderData?.["routes/story.$storyid"]?.story;
if (!story?.parts) return [];
return story.parts.map((p, i) => ({
id: String(p.id),
title: p.title || `Chapter ${i + 1}`,
number: i + 1,
language: story.language?.name?.toLowerCase() || "en",
index: i
}));
}
async findChapterPages(chapterId) {
const html = await fetch(`https://www.wattpad.com/amp/${chapterId}`).then(r => r.text());
// Usamos la versión AMP para obtener el contenido limpio en una sola petición
const url = `${this.baseUrl}/amp/${chapterId}`;
const res = await fetch(url, { headers: this.headers });
const html = await res.text();
const $ = this.cheerio.load(html);
const title = $('h2').first().text().trim();
const container = $('.story-body-type');
if (!container.length) return "";
if (!container.length) return "Content not available or paid story.";
// Limpieza de elementos basura
container.find('[data-media-type="image"]').remove();
const parts = [];
let content = "";
container.find('p').each((_, el) => {
const text = $(el)
.html()
.replace(/\u00A0/g, " ")
.replace(/[ \t]+/g, " ")
.trim();
if (title) content += `<h1>${title}</h1><br>`;
if (text) parts.push(`<p>${text}</p>`);
});
container.find('amp-img').each((_, el) => {
container.contents().each((_, el) => {
if (el.tagName === 'p') {
const text = $(el).text().trim();
if (text) content += `<p>${text}</p>`;
} else if (el.tagName === 'amp-img') {
const src = $(el).attr('src');
const w = $(el).attr('width');
const h = $(el).attr('height');
if (src) parts.push(`<img src="${src}" width="${w}" height="${h}">`);
if (src) content += `<img src="${src}" style="max-width:100%; display:block; margin: 10px auto;">`;
}
});
return (
(title ? `<h1>${title}</h1>\n\n` : "") +
parts.join("\n\n")
).trim();
return content;
}
}
module.exports = wattpad;
module.exports = Wattpad;

View File

@@ -2,65 +2,185 @@ class WeebCentral {
constructor() {
this.baseUrl = "https://weebcentral.com";
this.type = "book-board";
this.version = "1.0";
this.version = "1.1";
this.mediaType = "manga";
}
async fetch(url, options = {}) {
return fetch(url, {
...options,
headers: {
"User-Agent": "Mozilla/5.0",
...(options.headers || {}),
getFilters() {
return {
sort: {
label: "Sort By",
type: "select",
options: [
{ value: "Best Match", label: "Best Match" },
{ value: "Alphabet", label: "Alphabet" },
{ value: "Popularity", label: "Popularity" },
{ value: "Subscribers", label: "Subscribers" },
{ value: "Recently Added", label: "Recently Added" },
{ value: "Latest Updates", label: "Latest Updates" }
],
default: "Popularity"
},
});
order: {
label: "Sort Order",
type: "select",
options: [
{ value: "Descending", label: "Descending" },
{ value: "Ascending", label: "Ascending" }
],
default: "Descending"
},
official: {
label: "Official Translation",
type: "select",
options: [
{ value: "Any", label: "Any" },
{ value: "True", label: "True" },
{ value: "False", label: "False" }
],
default: "Any"
},
status: {
label: "Status",
type: "multiselect",
options: [
{ value: "Ongoing", label: "Ongoing" },
{ value: "Complete", label: "Complete" },
{ value: "Hiatus", label: "Hiatus" },
{ value: "Canceled", label: "Canceled" }
]
},
type: {
label: "Type",
type: "multiselect",
options: [
{ value: "Manga", label: "Manga" },
{ value: "Manhwa", label: "Manhwa" },
{ value: "Manhua", label: "Manhua" },
{ value: "OEL", label: "OEL" }
]
},
tags: {
label: "Tags",
type: "multiselect",
options: [
{ value: "Action", label: "Action" },
{ value: "Adult", label: "Adult" },
{ value: "Adventure", label: "Adventure" },
{ value: "Comedy", label: "Comedy" },
{ value: "Doujinshi", label: "Doujinshi" },
{ value: "Drama", label: "Drama" },
{ value: "Ecchi", label: "Ecchi" },
{ value: "Fantasy", label: "Fantasy" },
{ value: "Gender Bender", label: "Gender Bender" },
{ value: "Harem", label: "Harem" },
{ value: "Hentai", label: "Hentai" },
{ value: "Historical", label: "Historical" },
{ value: "Horror", label: "Horror" },
{ value: "Isekai", label: "Isekai" },
{ value: "Josei", label: "Josei" },
{ value: "Lolicon", label: "Lolicon" },
{ value: "Martial Arts", label: "Martial Arts" },
{ value: "Mature", label: "Mature" },
{ value: "Mecha", label: "Mecha" },
{ value: "Mystery", label: "Mystery" },
{ value: "Psychological", label: "Psychological" },
{ value: "Romance", label: "Romance" },
{ value: "School Life", label: "School Life" },
{ value: "Sci-fi", label: "Sci-fi" },
{ value: "Seinen", label: "Seinen" },
{ value: "Shotacon", label: "Shotacon" },
{ value: "Shoujo", label: "Shoujo" },
{ value: "Shoujo Ai", label: "Shoujo Ai" },
{ value: "Shounen", label: "Shounen" },
{ value: "Shounen Ai", label: "Shounen Ai" },
{ value: "Slice of Life", label: "Slice of Life" },
{ value: "Smut", label: "Smut" },
{ value: "Sports", label: "Sports" },
{ value: "Supernatural", label: "Supernatural" },
{ value: "Tragedy", label: "Tragedy" },
{ value: "Yaoi", label: "Yaoi" },
{ value: "Yuri", label: "Yuri" },
{ value: "Other", label: "Other" }
]
}
};
}
async search(queryObj) {
const query = queryObj.query || "";
const form = new URLSearchParams();
form.set("text", query);
const res = await this.fetch(
`${this.baseUrl}/search/simple?location=main`,
{
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"HX-Request": "true",
"HX-Trigger": "quick-search-input",
"HX-Target": "quick-search-result",
"HX-Current-URL": `${this.baseUrl}/`,
},
body: form.toString(),
get headers() {
return {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Referer": this.baseUrl + "/"
};
}
);
async search({ query, page = 1, filters }) {
const limit = 32;
const offset = (page - 1) * limit;
const url = new URL(`${this.baseUrl}/search/data`);
// Parámetros básicos
url.searchParams.set("limit", limit.toString());
url.searchParams.set("offset", offset.toString());
url.searchParams.set("display_mode", "Full Display");
// Texto de búsqueda
if (query && query.trim().length > 0) {
url.searchParams.set("text", query.trim());
}
// Filtros
if (filters) {
if (filters.sort) url.searchParams.set("sort", filters.sort);
if (filters.order) url.searchParams.set("order", filters.order);
if (filters.official) url.searchParams.set("official", filters.official);
// Multiselects
if (filters.status) {
const vals = String(filters.status).split(',');
vals.forEach(v => { if(v.trim()) url.searchParams.append("included_status", v.trim()); });
}
if (filters.type) {
const vals = String(filters.type).split(',');
vals.forEach(v => { if(v.trim()) url.searchParams.append("included_type", v.trim()); });
}
if (filters.tags) {
const vals = String(filters.tags).split(',');
vals.forEach(v => { if(v.trim()) url.searchParams.append("included_tag", v.trim()); });
}
} else if (!query) {
// Default para "Latest" si no hay query ni filtros
url.searchParams.set("sort", "Popularity");
}
const res = await fetch(url.toString(), { headers: this.headers });
if (!res.ok) return [];
const html = await res.text();
const $ = this.cheerio.load(html);
const results = [];
$("#quick-search-result > div > a").each((_, el) => {
const link = $(el).attr("href");
if (!link) return;
$("article > section > a").each((_, el) => {
const href = $(el).attr("href");
if (!href) return;
const idMatch = link.match(/\/series\/([^/]+)/);
const idMatch = href.match(/\/series\/([^/]+)/);
if (!idMatch) return;
const title = $(el).find(".flex-1").text().trim();
// Título es el último div sin clase
const title = $(el).find("div:not([class]):last-child").text().trim();
let image =
$(el).find("source").attr("srcset") ||
$(el).find("img").attr("src") ||
null;
// Imagen
let image = $(el).find("source").attr("srcset") || $(el).find("img").attr("src");
if (image) image = image.replace("small", "normal");
results.push({
id: idMatch[1],
title,
image,
rating: null,
type: "book",
image: image || "",
type: "book"
});
});
@@ -68,83 +188,76 @@ class WeebCentral {
}
async getMetadata(id) {
const res = await this.fetch(`${this.baseUrl}/series/${id}`, {
headers: { Referer: `${this.baseUrl}/series/${id}` },
});
const res = await fetch(`${this.baseUrl}/series/${id}`, { headers: this.headers });
if (!res.ok) throw new Error("Metadata failed");
const html = await res.text();
const $ = this.cheerio.load(html);
const title =
$("section.md\\:w-8\\/12 h1").first().text().trim() || "";
// Sección 1: Info (Imagen, Autor, Tags, Status)
const section1 = $("section[x-data] > section").eq(0);
const genres = [];
$("li strong")
.filter((_, el) => $(el).text().includes("Tags"))
.parent()
.find("a")
.each((_, a) => {
genres.push($(a).text().trim());
let image = section1.find("source").attr("srcset") || section1.find("img").attr("src");
if(image) image = image.replace("small", "normal");
const authors = [];
section1.find("li:has(strong:contains('Author')) > span > a").each((_, el) => {
authors.push($(el).text().trim());
});
const status =
$("li strong")
.filter((_, el) => $(el).text().includes("Status"))
.parent()
.find("a")
.first()
.text()
.trim() || "unknown";
const genres = [];
section1.find("li:has(strong:contains('Tag'), strong:contains('Type')) a").each((_, el) => {
genres.push($(el).text().trim());
});
const published =
$("li strong")
.filter((_, el) => $(el).text().includes("Released"))
.parent()
.find("span")
.first()
.text()
.trim() || "";
const statusRaw = section1.find("li:has(strong:contains('Status')) > a").text().trim().toLowerCase();
let status = "unknown";
if (statusRaw.includes("ongoing")) status = "ongoing";
else if (statusRaw.includes("complete")) status = "completed";
else if (statusRaw.includes("hiatus")) status = "hiatus";
else if (statusRaw.includes("canceled")) status = "cancelled";
const summary =
$("li strong")
.filter((_, el) => $(el).text().includes("Description"))
.parent()
.find("p")
.text()
.trim() || "";
// Sección 2: Título y Descripción
const section2 = $("section[x-data] > section").eq(1);
const title = section2.find("h1").first().text().trim();
const image =
$("section.flex picture source").attr("srcset") ||
$("section.flex picture img").attr("src") ||
null;
let descText = section2.find("li:has(strong:contains('Description')) > p").text().trim();
descText = descText.replace("NOTE:", "\n\nNOTE:");
// Añadir series relacionadas y nombres alternativos a la descripción (como en la app)
const related = section2.find("li:has(strong:contains('Related Series')) li");
if (related.length > 0) {
descText += "\n\nRelated Series:";
related.each((_, el) => {
descText += `\n${$(el).text().trim()}`;
});
}
const alts = section2.find("li:has(strong:contains('Associated Name')) li");
if (alts.length > 0) {
descText += "\n\nAssociated Names:";
alts.each((_, el) => {
descText += `\n${$(el).text().trim()}`;
});
}
return {
id,
title,
format: "MANGA",
score: 0,
genres: genres.join(", "),
genres,
status,
published,
summary,
chapters: "???",
image,
summary: descText,
chapters: 0,
author: authors.join(", "),
image: image || ""
};
}
async findChapters(mangaId) {
const res = await this.fetch(
`${this.baseUrl}/series/${mangaId}/full-chapter-list`,
{
headers: {
"HX-Request": "true",
"HX-Target": "chapter-list",
"HX-Current-URL": `${this.baseUrl}/series/${mangaId}`,
Referer: `${this.baseUrl}/series/${mangaId}`,
},
}
);
const res = await fetch(`${this.baseUrl}/series/${mangaId}/full-chapter-list`, { headers: this.headers });
if (!res.ok) return [];
const html = await res.text();
const $ = this.cheerio.load(html);
@@ -152,25 +265,29 @@ class WeebCentral {
const chapters = [];
const numRegex = /(\d+(?:\.\d+)?)/;
$("div.flex.items-center").each((_, el) => {
const a = $(el).find("a");
if (!a.length) return;
const href = a.attr("href");
$("div[x-data] > a").each((_, el) => {
const href = $(el).attr("href");
if (!href) return;
const idMatch = href.match(/\/chapters\/([^/]+)/);
if (!idMatch) return;
const title = a.find("span.grow > span").first().text().trim();
const titleElement = $(el).find("span.flex > span").first();
const title = titleElement.text().trim();
const numMatch = title.match(numRegex);
// Intentar detectar scanlator por el color del stroke del SVG (imitando la lógica de Kotlin)
let scanlator = null;
const svgStroke = $(el).find("svg").attr("stroke");
if (svgStroke === "#d8b4fe") scanlator = "Official"; // Color morado en WeebCentral indica oficial
chapters.push({
id: idMatch[1],
title,
number: numMatch ? Number(numMatch[1]) : 0,
releaseDate: null,
index: 0,
scanlator,
releaseDate: null, // La fecha requiere parseo complejo, lo omitimos por ahora
index: 0
});
});
@@ -180,23 +297,19 @@ class WeebCentral {
}
async findChapterPages(chapterId) {
const res = await this.fetch(
const res = await fetch(
`${this.baseUrl}/chapters/${chapterId}/images?is_prev=False&reading_style=long_strip`,
{
headers: {
"HX-Request": "true",
"HX-Current-URL": `${this.baseUrl}/chapters/${chapterId}`,
Referer: `${this.baseUrl}/chapters/${chapterId}`,
},
}
{ headers: this.headers }
);
if (!res.ok) return [];
const html = await res.text();
const $ = this.cheerio.load(html);
const pages = [];
$("section.flex-1 img").each((i, el) => {
$("section[x-data~='scroll'] > img").each((i, el) => {
const src = $(el).attr("src");
if (src) {
pages.push({
@@ -207,19 +320,6 @@ class WeebCentral {
}
});
if (pages.length === 0) {
$("img").each((i, el) => {
const src = $(el).attr("src");
if (src) {
pages.push({
url: src,
index: i,
headers: { Referer: this.baseUrl },
});
}
});
}
return pages;
}
}

View File

@@ -6,7 +6,8 @@
"description": "Anime streaming provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/Anicrush.js",
"domain": "https://anicrush.to/"
"icon": "https://anicrush.to/favicon.ico",
"lang": "en"
},
"AniDream": {
"name": "AniDream",
@@ -14,7 +15,8 @@
"description": "Anime streaming provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/AniDream.js",
"domain": "https://anidream.cc/"
"icon": "https://anidream.cc/favicon.ico",
"lang": "ita"
},
"Animekai": {
"name": "Animekai",
@@ -22,7 +24,8 @@
"description": "Anime streaming provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/Animekai.js",
"domain": "https://animekai.to/"
"icon": "https://play-lh.googleusercontent.com/lwR3a_qUxIKBkNJdwZl5gqed9Tev9KNM7LEdcgYx5TjWpqq2EAt7ZUdd-iQgIq6kqb2n-9G7-uihwlGBkJ0THg=w240-h480-rw",
"lang": "en"
},
"AnimePahe": {
"name": "AnimePahe",
@@ -30,7 +33,8 @@
"description": "Anime streaming provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/AnimePahe.js",
"domain": "https://animepahe.ru/"
"domain": "https://animepahe.si/favicon.ico",
"lang": "en"
},
"OppaiStream": {
"name": "OppaiStream",
@@ -38,7 +42,8 @@
"description": "Anime streaming provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/OppaiStream.js",
"domain": "https://oppaistream.to/",
"icon": "https://oppai.stream/assets/logo/favicon.ico?v=1",
"lang": "en",
"nsfw": true
},
"AnimeAV1": {
@@ -47,7 +52,48 @@
"description": "Anime provider with dubs and hard subs in spanish.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/AnimeAV1.js",
"domain": "https://animeav1.com/"
"icon": "https://animeav1.com/favicon.png",
"lang": "es"
},
"HentaiLA": {
"name": "HentaiLA",
"type": "anime-board",
"description": "Anime nsfw provider with hard subs in spanish.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/hentaila.js",
"icon": "https://hentaila.com/favicon.ico",
"nsfw": true,
"lang": "es"
},
"MissAV": {
"name": "MissAV",
"type": "anime-board",
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/missav.js",
"icon": "https://missav.live/img/favicon.ico",
"nsfw": true,
"lang": "jp"
},
"Rouvideo": {
"name": "Rouvideo",
"type": "anime-board",
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/rouvideo.js",
"icon": "https://rou.video/favicon-32x32.png",
"nsfw": true,
"lang": "jp"
},
"xvideos": {
"name": "xvideos",
"type": "anime-board",
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/xvideos.js",
"icon": "https://static-cdn77.xvideos-cdn.com/v3/img/skins/default/logo/xv.white.180.png",
"nsfw": true,
"lang": "multi"
},
"Anizone": {
"name": "Anizone",
@@ -55,7 +101,8 @@
"description": "Multi language anime provider, soft subs and dubs.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/AniZone.js",
"domain": "https://anizone.to/"
"icon": "",
"lang": "multi"
},
"animepictures": {
"name": "Anime Pictures",
@@ -63,18 +110,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/animepictures.js",
"domain": "https://anime-pictures.net/",
"nsfw": true
},
"asmhentai": {
"name": "ASM Hentai",
"type": "book-board",
"description": "Adult manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/asmhentai.js",
"domain": "https://asmhentai.com/",
"nsfw": true,
"broken": true
"icon": "https://anime-pictures.net/favicon.ico"
},
"gelbooru": {
"name": "Gelbooru",
@@ -82,7 +118,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/gelbooru.js",
"domain": "https://gelbooru.com/",
"icon": "https://gelbooru.com/favicon.png",
"nsfw": true
},
"giphy": {
@@ -91,7 +127,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/giphy.js",
"domain": "https://giphy.com/"
"icon": "https://giphy.com/static/img/favicon.png"
},
"HiAnime": {
"name": "HiAnime",
@@ -99,16 +135,8 @@
"description": "English anime provider with soft subs and dubs",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/anime/HiAnime.js",
"domain": "https://hianime.to/"
},
"lightnovelworld": {
"name": "Lightnovelworld",
"type": "book-board",
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/lightnovelworld.js",
"domain": "https://lightnovelworld.org/",
"broken": true
"icon": "https://hianime.to/favicon.ico",
"lang": "en"
},
"mangadex": {
"name": "Mangadex",
@@ -116,7 +144,8 @@
"description": "English manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/mangadex.js",
"domain": "https://mangadex.org/"
"icon": "https://mangadex.org/favicon.ico",
"lang": "en"
},
"Comix": {
"name": "Comix",
@@ -124,7 +153,8 @@
"description": "English manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/comix.js",
"domain": "https://comix.to/"
"icon": "",
"lang": "en"
},
"MangaPill": {
"name": "MangaPill",
@@ -132,7 +162,8 @@
"description": "English manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/mangapill.js",
"domain": "https://mangafire.to/"
"icon": "https://mangapill.com/static/favicon/favicon-32x32.png",
"lang": "en"
},
"MangaFire": {
"name": "MangaFire",
@@ -140,7 +171,8 @@
"description": "Multi language manga provider",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/mangafire.js",
"domain": "https://mangafire.to/"
"icon": "https://s.mfcdn.cc/assets/sites/mangafire/favicon.png?v4",
"lang": "multi"
},
"WeebCentral": {
"name": "WeebCentral",
@@ -148,15 +180,8 @@
"description": "English manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/weebcentral.js",
"domain": "https://weebcentral.com/"
},
"mangapark": {
"name": "Mangapark",
"type": "book-board",
"description": "English manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/mangapark.js",
"domain": "https://mangapark.io/"
"icon": "https://weebcentral.com/favicon.ico",
"lang": "en"
},
"nhentai": {
"name": "nhentai",
@@ -164,7 +189,8 @@
"description": "Adult manga provider.",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/nhentai.js",
"domain": "https://nhentai.net/",
"icon": "https://nhentai.net/static/favicon.ico",
"lang": "multi",
"nsfw": true
},
"novelbin": {
@@ -173,7 +199,8 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/novelbin.js",
"domain": "https://novelbin.me/"
"icon": "https://novelbin.me/img/favicon.ico?v=1.68",
"lang": "en"
},
"novelfire": {
"name": "NovelFire",
@@ -181,7 +208,8 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/novelfire.js",
"domain": "https://novelfire.net/"
"icon": "https://novelfire.net/logo.ico?v=1.9",
"lang": "en"
},
"realbooru": {
"name": "Realbooru",
@@ -189,7 +217,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/realbooru.js",
"domain": "https://realbooru.com/",
"icon": "https://realbooru.com/favicon-32x32.png?v=1",
"nsfw": true
},
"rule34": {
@@ -198,7 +226,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/rule34.js",
"domain": "https://rule34.xxx/",
"icon": "https://rule34.xxx/favicon.ico?v=2",
"nsfw": true
},
"tenor": {
@@ -207,7 +235,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/tenor.js",
"domain": "https://tenor.com/"
"icon": "https://tenor.com/assets/img/favicon/favicon-16x16.png"
},
"waifupics": {
"name": "Waifupics",
@@ -215,7 +243,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/waifupics.js",
"domain": "https://waifu.pics/"
"domain": "https://waifu.pics/favicon.ico"
},
"wattpad": {
"name": "Wattpad",
@@ -223,7 +251,8 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/book/wattpad.js",
"domain": "https://www.wattpad.com/"
"icon": "https://www.wattpad.com/wp-web-assets/images/wattpad-logo.svg",
"lang": "en"
},
"ZeroChan": {
"name": "ZeroChan",
@@ -231,7 +260,7 @@
"description": ".",
"author": "lenafx",
"entry": "https://git.waifuboard.app/ItsSkaiya/WaifuBoard-Extensions/raw/branch/main/image/ZeroChan.js",
"domain": "https://www.zerochan.net/"
"icon": "https://static.zerochan.net/favicon.png"
}
}
}