updates and new extensions
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
class AnimeAV1 {
|
||||
|
||||
constructor() {
|
||||
this.type = "anime-board";
|
||||
this.version = "1.2"
|
||||
this.version = "1.3";
|
||||
this.api = "https://animeav1.com";
|
||||
}
|
||||
|
||||
getSettings() {
|
||||
return {
|
||||
episodeServers: ["HLS", "HLS-DUB"],
|
||||
episodeServers: ["HLS"],
|
||||
supportsDub: true,
|
||||
};
|
||||
}
|
||||
@@ -21,10 +20,9 @@ class AnimeAV1 {
|
||||
});
|
||||
|
||||
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}`,
|
||||
@@ -34,70 +32,37 @@ class AnimeAV1 {
|
||||
}
|
||||
|
||||
async getMetadata(id) {
|
||||
const html = await fetch(`${this.api}/media/${id}`).then(r => r.text());
|
||||
const html = await fetch(`${this.api}/media/${id}`).then((r) => r.text());
|
||||
const parsed = this.parseSvelteData(html);
|
||||
const media = parsed.find(x => x?.data?.media)?.data.media ?? {};
|
||||
const media = parsed.find((x) => x?.data?.media)?.data.media ?? {};
|
||||
|
||||
// IMAGE
|
||||
const imageMatch = html.match(/<img[^>]*class="aspect-poster[^"]*"[^>]*src="([^"]+)"/i);
|
||||
const image = imageMatch ? imageMatch[1] : null;
|
||||
|
||||
// BLOCK INFO (STATUS, SEASON, YEAR)
|
||||
const infoBlockMatch = html.match(
|
||||
/<div class="flex flex-wrap items-center gap-2 text-sm">([\s\S]*?)<\/div>/
|
||||
const imageMatch = html.match(
|
||||
/<img[^>]*class="aspect-poster[^"]*"[^>]*src="([^"]+)"/i
|
||||
);
|
||||
|
||||
let status = media.status ?? "Unknown";
|
||||
let season = media.seasons ?? null;
|
||||
let year = media.startDate ? Number(media.startDate.slice(0, 4)) : null;
|
||||
|
||||
if (infoBlockMatch) {
|
||||
const raw = infoBlockMatch[1];
|
||||
|
||||
// Extraer spans internos
|
||||
const spans = [...raw.matchAll(/<span[^>]*>([^<]+)<\/span>/g)].map(m => m[1].trim());
|
||||
|
||||
// EJEMPLO:
|
||||
// ["TV Anime", "•", "2025", "•", "Temporada Otoño", "•", "En emisión"]
|
||||
|
||||
const clean = spans.filter(x => x !== "•");
|
||||
|
||||
// YEAR
|
||||
const yearMatch = clean.find(x => /^\d{4}$/.test(x));
|
||||
if (yearMatch) year = Number(yearMatch);
|
||||
|
||||
// SEASON (el que contiene "Temporada")
|
||||
const seasonMatch = clean.find(x => x.toLowerCase().includes("temporada"));
|
||||
if (seasonMatch) season = seasonMatch;
|
||||
|
||||
// STATUS (normalmente "En emisión", "Finalizado", etc)
|
||||
const statusMatch = clean.find(x =>
|
||||
/emisión|finalizado|completado|pausa|cancelado/i.test(x)
|
||||
);
|
||||
if (statusMatch) status = statusMatch;
|
||||
}
|
||||
const image = imageMatch ? imageMatch[1] : null;
|
||||
|
||||
return {
|
||||
title: media.title ?? "Unknown",
|
||||
summary: media.synopsis ?? "No summary available",
|
||||
episodes: media.episodesCount ?? 0,
|
||||
characters: [],
|
||||
season,
|
||||
status,
|
||||
season: media.seasons ?? null,
|
||||
status: media.status ?? "Unknown",
|
||||
studio: "Unknown",
|
||||
score: media.score ?? 0,
|
||||
year,
|
||||
genres: media.genres?.map(g => g.name) ?? [],
|
||||
image
|
||||
year: media.startDate
|
||||
? Number(media.startDate.slice(0, 4))
|
||||
: null,
|
||||
genres: media.genres?.map((g) => g.name) ?? [],
|
||||
image,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
async findEpisodes(id) {
|
||||
const html = await fetch(`${this.api}/media/${id}`).then(r => r.text());
|
||||
const html = await fetch(`${this.api}/media/${id}`).then((r) => r.text());
|
||||
const parsed = this.parseSvelteData(html);
|
||||
|
||||
const media = parsed.find(x => x?.data?.media)?.data?.media;
|
||||
const media = parsed.find((x) => x?.data?.media)?.data?.media;
|
||||
if (!media?.episodes) throw new Error("No se encontró media.episodes");
|
||||
|
||||
return media.episodes.map((ep, i) => ({
|
||||
@@ -108,71 +73,94 @@ class AnimeAV1 {
|
||||
}));
|
||||
}
|
||||
|
||||
async findEpisodeServer(episodeOrId, _server) {
|
||||
const ep = typeof episodeOrId === "string"
|
||||
? (() => { try { return JSON.parse(episodeOrId); } catch { return { id: episodeOrId }; } })()
|
||||
: episodeOrId;
|
||||
async findEpisodeServer(episodeOrId, _server, category = "sub") {
|
||||
const ep =
|
||||
typeof episodeOrId === "string"
|
||||
? (() => {
|
||||
try {
|
||||
return JSON.parse(episodeOrId);
|
||||
} catch {
|
||||
return { id: episodeOrId };
|
||||
}
|
||||
})()
|
||||
: episodeOrId;
|
||||
|
||||
const pageUrl = ep.url ?? (
|
||||
typeof ep.id === "string" && ep.id.includes("$")
|
||||
? `${this.api}/media/${ep.id.split("$")[0]}/${ep.number ?? ep.id.split("$")[1]}`
|
||||
: undefined
|
||||
);
|
||||
|
||||
let pageUrl = ep.url;
|
||||
|
||||
if (!pageUrl && typeof ep.id === "string") {
|
||||
if (ep.id.includes("$")) {
|
||||
const [slug, num] = ep.id.split("$");
|
||||
pageUrl = `${this.api}/media/${slug}/${ep.number ?? num}`;
|
||||
} else {
|
||||
pageUrl = `${this.api}/media/${ep.id}/${ep.number}`;
|
||||
}
|
||||
}
|
||||
|
||||
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, {
|
||||
headers: { Cookie: "__ddg1_=;__ddg2_=;" },
|
||||
}).then(r => r.text());
|
||||
|
||||
const html = await fetch(pageUrl).then((r) => r.text());
|
||||
const parsedData = this.parseSvelteData(html);
|
||||
const entry = parsedData.find(x => x?.data?.embeds) || parsedData[3];
|
||||
const entry = parsedData.find((x) => x?.data?.embeds);
|
||||
const embeds = entry?.data?.embeds;
|
||||
if (!embeds) throw new Error("No se encontraron 'embeds' en los datos del episodio.");
|
||||
if (!embeds) throw new Error("No embeds encontrados");
|
||||
|
||||
const selectedEmbeds =
|
||||
_server === "HLS"
|
||||
? embeds.SUB ?? []
|
||||
: _server === "HLS-DUB"
|
||||
? embeds.DUB ?? []
|
||||
: (() => { throw new Error(`Servidor desconocido: ${_server}`); })();
|
||||
const list =
|
||||
category === "dub"
|
||||
? embeds.DUB
|
||||
: embeds.SUB;
|
||||
|
||||
if (!selectedEmbeds.length)
|
||||
throw new Error(`No hay mirrors disponibles para ${_server === "HLS" ? "SUB" : "DUB"}.`);
|
||||
if (!Array.isArray(list))
|
||||
throw new Error(`No hay streams ${category.toUpperCase()}`);
|
||||
|
||||
const match = selectedEmbeds.find(m =>
|
||||
(m.url || "").includes("zilla-networks.com/play/")
|
||||
const hls = list.find(
|
||||
(m) =>
|
||||
m.server === "HLS" &&
|
||||
m.url?.includes("zilla-networks.com/play/")
|
||||
);
|
||||
|
||||
if (!match)
|
||||
throw new Error(`No se encontró ningún embed de ZillaNetworks en ${_server}.`);
|
||||
if (!hls)
|
||||
throw new Error(`No se encontró stream HLS ${category.toUpperCase()}`);
|
||||
|
||||
return {
|
||||
server: _server,
|
||||
headers: { Referer: 'null' },
|
||||
server: "HLS",
|
||||
headers: { Referer: "null" },
|
||||
videoSources: [
|
||||
{
|
||||
url: match.url.replace("/play/", "/m3u8/"),
|
||||
url: hls.url.replace("/play/", "/m3u8/"),
|
||||
type: "m3u8",
|
||||
quality: "auto",
|
||||
subtitles: [],
|
||||
subOrDub: category,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
parseSvelteData(html) {
|
||||
const scriptMatch = html.match(/<script[^>]*>\s*({[^<]*__sveltekit_[\s\S]*?)<\/script>/i);
|
||||
if (!scriptMatch) throw new Error("No se encontró bloque SvelteKit en el HTML.");
|
||||
const scriptMatch = html.match(
|
||||
/<script[^>]*>\s*({[^<]*__sveltekit_[\s\S]*?)<\/script>/i
|
||||
);
|
||||
if (!scriptMatch) throw new Error("SvelteKit block not found");
|
||||
|
||||
const dataMatch = scriptMatch[1].match(/data:\s*(\[[\s\S]*?\])\s*,\s*form:/);
|
||||
if (!dataMatch) throw new Error("No se encontró el bloque 'data' en el script SvelteKit.");
|
||||
const dataMatch = scriptMatch[1].match(
|
||||
/data:\s*(\[[\s\S]*?\])\s*,\s*form:/
|
||||
);
|
||||
if (!dataMatch) throw new Error("SvelteKit data block not found");
|
||||
|
||||
const jsArray = dataMatch[1];
|
||||
try {
|
||||
return new Function(`"use strict"; return (${jsArray});`)();
|
||||
} catch {
|
||||
const cleaned = jsArray.replace(/\bvoid 0\b/g, "null").replace(/undefined/g, "null");
|
||||
const cleaned = jsArray
|
||||
.replace(/\bvoid 0\b/g, "null")
|
||||
.replace(/undefined/g, "null");
|
||||
return new Function(`"use strict"; return (${cleaned});`)();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user