updated marketplace and extensions
This commit is contained in:
164
anime/AniZone.js
Normal file
164
anime/AniZone.js
Normal file
@@ -0,0 +1,164 @@
|
||||
class Anizone {
|
||||
constructor() {
|
||||
this.type = "anime-board";
|
||||
this.version = "1.0";
|
||||
this.api = "https://anizone.to";
|
||||
}
|
||||
|
||||
getSettings() {
|
||||
return {
|
||||
episodeServers: ["HLS"],
|
||||
supportsDub: true,
|
||||
};
|
||||
}
|
||||
|
||||
async search(queryObj) {
|
||||
const query = queryObj.query ?? "";
|
||||
|
||||
const res = await fetch(
|
||||
`${this.api}/anime?search=${encodeURIComponent(query)}`,
|
||||
{
|
||||
headers: {
|
||||
accept: "*/*",
|
||||
referer: "https://anizone.to/",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const html = await res.text();
|
||||
|
||||
const itemRegex =
|
||||
/<div[^>]*class="relative overflow-hidden h-26 rounded-lg[\s\S]*?<img[^>]*src="([^"]+)"[^>]*alt="([^"]+)"[\s\S]*?<a[^>]*href="([^"]+)"[^>]*title="([^"]+)"/g;
|
||||
|
||||
const results = [];
|
||||
let match;
|
||||
|
||||
while ((match = itemRegex.exec(html)) !== null) {
|
||||
const [, image, altTitle, href, title] = match;
|
||||
const animeId = href.split("/").pop();
|
||||
|
||||
// detectar sub / dub desde el episodio 1
|
||||
let subOrDub = "sub";
|
||||
|
||||
try {
|
||||
const epHtml = await fetch(`${this.api}/anime/${animeId}/1`, {
|
||||
headers: {
|
||||
referer: "https://anizone.to/",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
},
|
||||
}).then(r => r.text());
|
||||
|
||||
const audioMatch = epHtml.match(
|
||||
/<div class="text-xs flex flex-wrap gap-1">([\s\S]*?)<\/div>/
|
||||
);
|
||||
|
||||
if (audioMatch) {
|
||||
const block = audioMatch[1];
|
||||
const hasJP = /Japanese/i.test(block);
|
||||
const hasOther = /(English|Spanish|French|German|Italian)/i.test(block);
|
||||
|
||||
if (hasJP && hasOther) subOrDub = "both";
|
||||
else if (hasOther) subOrDub = "dub";
|
||||
}
|
||||
} catch {}
|
||||
|
||||
results.push({
|
||||
id: animeId,
|
||||
title: title || altTitle,
|
||||
image,
|
||||
url: href,
|
||||
subOrDub,
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async getMetadata(id) {
|
||||
// HARDCODED de momento
|
||||
return {
|
||||
id,
|
||||
title: "Unknown",
|
||||
summary: "",
|
||||
episodes: 0,
|
||||
status: "unknown",
|
||||
season: null,
|
||||
year: null,
|
||||
genres: [],
|
||||
score: 0,
|
||||
image: null,
|
||||
};
|
||||
}
|
||||
|
||||
async findEpisodes(id) {
|
||||
const html = await fetch(`${this.api}/anime/${id}/1`).then(r => r.text());
|
||||
|
||||
const regex =
|
||||
/<a[^>]*href="([^"]*\/anime\/[^"]+?)"[^>]*>\s*<div[^>]*>\s*<div[^>]*class='[^']*min-w-10[^']*'[^>]*>(\d+)<\/div>\s*<div[^>]*class="[^"]*line-clamp-1[^"]*"[^>]*>([^<]+)<\/div>/g;
|
||||
|
||||
const episodes = [];
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(html)) !== null) {
|
||||
const [, href, num, title] = match;
|
||||
|
||||
episodes.push({
|
||||
id: href.split("/").pop(),
|
||||
number: Number(num),
|
||||
title: title.trim(),
|
||||
url: href,
|
||||
});
|
||||
}
|
||||
|
||||
return episodes;
|
||||
}
|
||||
|
||||
async findEpisodeServer(episode, server) {
|
||||
const html = await fetch(episode.url).then(r => r.text());
|
||||
|
||||
const srcMatch = html.match(
|
||||
/<media-player[^>]+src="([^"]+\.m3u8)"/i
|
||||
);
|
||||
if (!srcMatch) throw new Error("No m3u8 found");
|
||||
|
||||
const masterUrl = srcMatch[1];
|
||||
|
||||
const subtitles = [];
|
||||
const trackRegex =
|
||||
/<track[^>]+src=([^ >]+)[^>]*label="([^"]+)"[^>]*srclang="([^"]+)"[^>]*(default)?/gi;
|
||||
|
||||
let match;
|
||||
while ((match = trackRegex.exec(html)) !== null) {
|
||||
const [, src, label, lang, def] = match;
|
||||
subtitles.push({
|
||||
id: lang,
|
||||
url: src,
|
||||
language: label.trim(),
|
||||
isDefault: Boolean(def),
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
server,
|
||||
headers: {
|
||||
Origin: "https://anizone.to",
|
||||
Referer: "https://anizone.to/",
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
},
|
||||
videoSources: [
|
||||
{
|
||||
url: masterUrl,
|
||||
type: "m3u8",
|
||||
quality: "auto",
|
||||
subtitles,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Anizone;
|
||||
Reference in New Issue
Block a user