Add anime/animeav1/source.js
This commit is contained in:
171
anime/animeav1/source.js
Normal file
171
anime/animeav1/source.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
class AnimeAV1 {
|
||||||
|
constructor() {
|
||||||
|
this.type = "anime-board";
|
||||||
|
this.version = "1.0.0";
|
||||||
|
this.api = "https://animeav1.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettings() {
|
||||||
|
return {
|
||||||
|
episodeServers: ["HLS", "HLS-DUB"],
|
||||||
|
supportsDub: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async search(query) {
|
||||||
|
const q =
|
||||||
|
(query && typeof query === "object" && query.query)
|
||||||
|
? String(query.query)
|
||||||
|
: (typeof query === "string" ? query : "");
|
||||||
|
|
||||||
|
if (!q.trim()) return [];
|
||||||
|
|
||||||
|
const res = await fetch(`${this.api}/api/search`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ query: q }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) return [];
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (!Array.isArray(data)) return [];
|
||||||
|
|
||||||
|
return data
|
||||||
|
.map(anime => {
|
||||||
|
if (!anime || !anime.slug) return null;
|
||||||
|
return {
|
||||||
|
id: anime.slug,
|
||||||
|
title: anime.title || "Unknown",
|
||||||
|
url: `${this.api}/media/${anime.slug}`,
|
||||||
|
subOrDub: "both",
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMetadata(id) {
|
||||||
|
const slug = String(id || "").trim();
|
||||||
|
if (!slug) throw new Error("Missing id");
|
||||||
|
|
||||||
|
const html = await fetch(`${this.api}/media/${slug}`).then(r => r.text());
|
||||||
|
const parsed = this.parseSvelteData(html);
|
||||||
|
const media = parsed.find(x => x?.data?.media)?.data?.media || {};
|
||||||
|
|
||||||
|
let image = null;
|
||||||
|
const imageMatch = html.match(/<img[^>]*class="aspect-poster[^"]*"[^>]*src="([^"]+)"/i);
|
||||||
|
if (imageMatch) image = imageMatch[1];
|
||||||
|
|
||||||
|
let year = null;
|
||||||
|
if (media.startDate) {
|
||||||
|
const y = Number(String(media.startDate).slice(0, 4));
|
||||||
|
if (!Number.isNaN(y)) year = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: media.title || "Unknown",
|
||||||
|
summary: media.synopsis || "No summary available",
|
||||||
|
episodes: media.episodesCount || 0,
|
||||||
|
characters: [],
|
||||||
|
season: media.seasons || null,
|
||||||
|
status: media.status || "Unknown",
|
||||||
|
studio: "Unknown",
|
||||||
|
score: media.score || 0,
|
||||||
|
year,
|
||||||
|
genres: (media.genres || []).map(g => g?.name).filter(Boolean),
|
||||||
|
image,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async findEpisodes(id) {
|
||||||
|
const slug = String(id || "").trim();
|
||||||
|
if (!slug) throw new Error("Missing id");
|
||||||
|
|
||||||
|
const html = await fetch(`${this.api}/media/${slug}`).then(r => r.text());
|
||||||
|
const parsed = this.parseSvelteData(html);
|
||||||
|
const media = parsed.find(x => x?.data?.media)?.data?.media;
|
||||||
|
|
||||||
|
if (!media || !Array.isArray(media.episodes))
|
||||||
|
throw new Error("No episodes");
|
||||||
|
|
||||||
|
return media.episodes.map((ep, i) => {
|
||||||
|
const n = ep?.number ?? (i + 1);
|
||||||
|
return {
|
||||||
|
id: `${media.slug || slug}$${n}`,
|
||||||
|
number: n,
|
||||||
|
title: ep?.title || `Episode ${n}`,
|
||||||
|
url: `${this.api}/media/${media.slug || slug}/${n}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findEpisodeServer(episodeOrId, server) {
|
||||||
|
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]}`
|
||||||
|
: null);
|
||||||
|
|
||||||
|
if (!pageUrl) throw new Error("Missing episode url");
|
||||||
|
|
||||||
|
const html = await fetch(pageUrl, {
|
||||||
|
headers: { Referer: `${this.api}/` },
|
||||||
|
}).then(r => r.text());
|
||||||
|
|
||||||
|
const parsed = this.parseSvelteData(html);
|
||||||
|
const entry = parsed.find(x => x?.data?.embeds) || parsed[3];
|
||||||
|
const embeds = entry?.data?.embeds;
|
||||||
|
|
||||||
|
if (!embeds) throw new Error("No embeds");
|
||||||
|
|
||||||
|
const list =
|
||||||
|
server === "HLS" ? embeds.SUB :
|
||||||
|
server === "HLS-DUB" ? embeds.DUB :
|
||||||
|
null;
|
||||||
|
|
||||||
|
if (!Array.isArray(list) || !list.length)
|
||||||
|
throw new Error("No mirrors");
|
||||||
|
|
||||||
|
const match = list.find(m => String(m?.url || "").includes("zilla-networks.com/play/"));
|
||||||
|
if (!match) throw new Error("No valid source");
|
||||||
|
|
||||||
|
return {
|
||||||
|
server,
|
||||||
|
headers: { Referer: pageUrl },
|
||||||
|
videoSources: [
|
||||||
|
{
|
||||||
|
url: String(match.url).replace("/play/", "/m3u8/"),
|
||||||
|
type: "m3u8",
|
||||||
|
quality: "auto",
|
||||||
|
subtitles: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSvelteData(html) {
|
||||||
|
const scriptMatch = html.match(/<script[^>]*>\s*({[^<]*__sveltekit_[\s\S]*?)<\/script>/i);
|
||||||
|
if (!scriptMatch) throw new Error("Svelte data not found");
|
||||||
|
|
||||||
|
const dataMatch = scriptMatch[1].match(/data:\s*(\[[\s\S]*?\])\s*,\s*form:/);
|
||||||
|
if (!dataMatch) throw new Error("Data block missing");
|
||||||
|
|
||||||
|
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");
|
||||||
|
return new Function(`"use strict"; return (${cleaned});`)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AnimeAV1;
|
||||||
Reference in New Issue
Block a user