feat: add catalog, meta, posts, and stream modules for Animetsu provider

This commit is contained in:
himanshu8443
2025-07-27 11:02:34 +05:30
parent bf8ea22300
commit b18b4d23b4
8 changed files with 321 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
export const catalog = [
{
title: "Popular",
filter:
"/api/anime/search?query=&page=1&perPage=35&year=any&sort=favourites&season=any&format=any&status=any",
},
{
title: "Trending",
filter:
"/api/anime/search?query=&page=1&perPage=35&year=any&sort=trending&season=any&format=any&status=any",
},
{
title: "Top Rated",
filter:
"/api/anime/search?query=&page=1&perPage=35&year=any&sort=rating&season=any&format=any&status=any",
},
{
title: "Recently Updated",
filter:
"/api/anime/search?query=&page=1&perPage=35&year=any&sort=updated&season=any&format=any&status=any",
},
];
export const genres = [];

109
providers/animetsu/meta.ts Normal file
View File

@@ -0,0 +1,109 @@
import { Info, Link, ProviderContext } from "../types";
export const getMeta = async function ({
link,
providerContext,
}: {
link: string;
providerContext: ProviderContext;
}): Promise<Info> {
try {
const { axios } = providerContext;
const baseUrl = "https://backend.animetsu.to";
const url = `${baseUrl}/api/anime/info/${link}`;
const res = await axios.get(url, {
headers: {
Referer: "https://animetsu.to/",
},
});
const data = res.data;
const meta = {
title:
data.title?.english || data.title?.romaji || data.title?.native || "",
synopsis: data.description || "",
image:
data.coverImage?.extraLarge ||
data.coverImage?.large ||
data.coverImage?.medium ||
"",
tags: [data?.format, data?.status, ...(data?.genres || [])].filter(
Boolean
),
imdbId: "",
type: data.format === "MOVIE" ? "movie" : "series",
};
const linkList: Link[] = [];
// Get episodes data
try {
const episodesRes = await axios.get(`${baseUrl}/api/anime/eps/${link}`, {
headers: {
Referer: "https://animetsu.to/",
},
});
const episodes = episodesRes.data;
if (episodes && episodes.length > 0) {
const directLinks: Link["directLinks"] = [];
episodes.forEach((episode: any) => {
const title = `Episode ${episode.number}`;
const episodeLink = `${link}:${episode.number}`;
if (episodeLink && title) {
directLinks.push({
title,
link: episodeLink,
});
}
});
linkList.push({
title: meta.title,
directLinks: directLinks,
});
} else {
// Movie case - single episode
linkList.push({
title: meta.title,
directLinks: [
{
title: "Movie",
link: `${link}:1`,
},
],
});
}
} catch (episodeErr) {
console.error("Error fetching episodes:", episodeErr);
// Fallback for movie or single episode
linkList.push({
title: meta.title,
directLinks: [
{
title: meta.title,
link: `${link}:1`,
},
],
});
}
return {
...meta,
linkList: linkList,
};
} catch (err) {
console.error("animetsu meta error:", err);
return {
title: "",
synopsis: "",
image: "",
imdbId: "",
type: "movie",
linkList: [],
};
}
};

View File

@@ -0,0 +1,90 @@
import { Post, ProviderContext } from "../types";
export const getPosts = async function ({
filter,
page,
signal,
providerContext,
}: {
filter: string;
page: number;
providerValue: string;
signal: AbortSignal;
providerContext: ProviderContext;
}): Promise<Post[]> {
const { axios } = providerContext;
const baseUrl = "https://backend.animetsu.to";
// Parse filter to modify page parameter
const url = new URL(baseUrl + filter);
url.searchParams.set("page", page.toString());
return posts({ url: url.toString(), signal, axios });
};
export const getSearchPosts = async function ({
searchQuery,
page,
signal,
providerContext,
}: {
searchQuery: string;
page: number;
providerValue: string;
signal: AbortSignal;
providerContext: ProviderContext;
}): Promise<Post[]> {
const { axios } = providerContext;
const baseUrl = "https://backend.animetsu.to";
const url = `${baseUrl}/api/anime/search?query=${encodeURIComponent(
searchQuery
)}&page=${page}&perPage=35&year=any&sort=favourites&season=any&format=any&status=any`;
return posts({ url, signal, axios });
};
async function posts({
url,
signal,
axios,
}: {
url: string;
signal: AbortSignal;
axios: ProviderContext["axios"];
}): Promise<Post[]> {
try {
const res = await axios.get(url, {
signal,
headers: {
Referer: "https://animetsu.to/",
},
});
const data = res.data?.results;
const catalog: Post[] = [];
data?.map((element: any) => {
const title =
element.title?.english ||
element.title?.romaji ||
element.title?.native;
const link = element.id?.toString();
const image =
element.coverImage?.large ||
element.coverImage?.extraLarge ||
element.coverImage?.medium;
if (title && link && image) {
catalog.push({
title: title,
link: link,
image: image,
});
}
});
return catalog;
} catch (err) {
console.error("animetsu error ", err);
return [];
}
}

View File

@@ -0,0 +1,94 @@
import { Stream, ProviderContext } from "../types";
export const getStream = async function ({
link: id,
providerContext,
}: {
link: string;
providerContext: ProviderContext;
}): Promise<Stream[]> {
try {
const { axios } = providerContext;
const baseUrl = "https://backend.animetsu.to";
// Parse link format: "animeId:episodeNumber"
const [animeId, episodeNumber] = id.split(":");
if (!animeId || !episodeNumber) {
throw new Error("Invalid link format");
}
const servers = ["pahe", "zoro"]; // Available servers based on API structure
const streamLinks: Stream[] = [];
await Promise.all(
servers.map(async (server) => {
try {
const url = `${baseUrl}/api/anime/tiddies?server=${server}&id=${animeId}&num=${episodeNumber}&subType=sub`;
const res = await axios.get(url, {
headers: {
Referer: "https://animetsu.to/",
},
});
if (res.data && res.data.sources) {
res.data.sources.forEach((source: any) => {
streamLinks.push({
server: server,
link: source.url,
type: source.url.includes(".m3u8") ? "m3u8" : "mp4",
quality: source.quality,
headers: {
Referer: "https://animetsu.to/",
Origin: "https://animetsu.to",
},
subtitles: [], // No subtitle info provided in API response
});
});
}
} catch (e) {
console.log(`Error with server ${server}:`, e);
}
})
);
// Try dub version as well
await Promise.all(
servers.map(async (server) => {
try {
const url = `${baseUrl}/api/anime/tiddies?server=${server}&id=${animeId}&num=${episodeNumber}&subType=dub`;
const res = await axios.get(url, {
headers: {
Referer: "https://animetsu.to/",
},
});
if (res.data && res.data.sources) {
res.data.sources.forEach((source: any) => {
streamLinks.push({
server: `${server} (Dub)`,
link: source.url,
type: source.url.includes(".m3u8") ? "m3u8" : "mp4",
quality: source.quality,
headers: {
Referer: "https://animetsu.to/",
Origin: "https://animetsu.to",
},
subtitles: [],
});
});
}
} catch (e) {
console.log(`Error with server ${server} (dub):`, e);
}
})
);
return streamLinks;
} catch (err) {
console.error("animetsu stream error:", err);
return [];
}
};