mirror of
https://github.com/vega-org/vega-providers.git
synced 2026-04-17 23:51:44 +00:00
feat: add catalog, meta, posts, and stream modules for Animetsu provider
This commit is contained in:
1
dist/animetsu/catalog.js
vendored
Normal file
1
dist/animetsu/catalog.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.genres=exports.catalog=void 0,exports.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"}],exports.genres=[];
|
||||||
1
dist/animetsu/meta.js
vendored
Normal file
1
dist/animetsu/meta.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";var __awaiter=this&&this.__awaiter||function(thisArg,_arguments,P,generator){return new(P||(P=Promise))(function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator.throw(value))}catch(e){reject(e)}}function step(result){var value;result.done?resolve(result.value):(value=result.value,value instanceof P?value:new P(function(resolve){resolve(value)})).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.getMeta=void 0;const getMeta=function(_a){return __awaiter(this,arguments,void 0,function*({link:link,providerContext:providerContext}){var _b,_c,_d,_e,_f,_g;try{const{axios:axios}=providerContext,baseUrl="https://backend.animetsu.to",url=`${baseUrl}/api/anime/info/${link}`,data=(yield axios.get(url,{headers:{Referer:"https://animetsu.to/"}})).data,meta={title:(null===(_b=data.title)||void 0===_b?void 0:_b.english)||(null===(_c=data.title)||void 0===_c?void 0:_c.romaji)||(null===(_d=data.title)||void 0===_d?void 0:_d.native)||"",synopsis:data.description||"",image:(null===(_e=data.coverImage)||void 0===_e?void 0:_e.extraLarge)||(null===(_f=data.coverImage)||void 0===_f?void 0:_f.large)||(null===(_g=data.coverImage)||void 0===_g?void 0:_g.medium)||"",tags:[null==data?void 0:data.format,null==data?void 0:data.status,...(null==data?void 0:data.genres)||[]].filter(Boolean),imdbId:"",type:"MOVIE"===data.format?"movie":"series"},linkList=[];try{const episodes=(yield axios.get(`${baseUrl}/api/anime/eps/${link}`,{headers:{Referer:"https://animetsu.to/"}})).data;if(episodes&&episodes.length>0){const directLinks=[];episodes.forEach(episode=>{const title=`Episode ${episode.number}`,episodeLink=`${link}:${episode.number}`;episodeLink&&title&&directLinks.push({title:title,link:episodeLink})}),linkList.push({title:meta.title,directLinks:directLinks})}else linkList.push({title:meta.title,directLinks:[{title:"Movie",link:`${link}:1`}]})}catch(episodeErr){linkList.push({title:meta.title,directLinks:[{title:meta.title,link:`${link}:1`}]})}return Object.assign(Object.assign({},meta),{linkList:linkList})}catch(err){return{title:"",synopsis:"",image:"",imdbId:"",type:"movie",linkList:[]}}})};exports.getMeta=getMeta;
|
||||||
1
dist/animetsu/posts.js
vendored
Normal file
1
dist/animetsu/posts.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";var __awaiter=this&&this.__awaiter||function(thisArg,_arguments,P,generator){return new(P||(P=Promise))(function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator.throw(value))}catch(e){reject(e)}}function step(result){var value;result.done?resolve(result.value):(value=result.value,value instanceof P?value:new P(function(resolve){resolve(value)})).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.getSearchPosts=exports.getPosts=void 0;const getPosts=function(_a){return __awaiter(this,arguments,void 0,function*({filter:filter,page:page,signal:signal,providerContext:providerContext}){const{axios:axios}=providerContext,url=new URL("https://backend.animetsu.to"+filter);return url.searchParams.set("page",page.toString()),posts({url:url.toString(),signal:signal,axios:axios})})};exports.getPosts=getPosts;const getSearchPosts=function(_a){return __awaiter(this,arguments,void 0,function*({searchQuery:searchQuery,page:page,signal:signal,providerContext:providerContext}){const{axios:axios}=providerContext;return posts({url:`https://backend.animetsu.to/api/anime/search?query=${encodeURIComponent(searchQuery)}&page=${page}&perPage=35&year=any&sort=favourites&season=any&format=any&status=any`,signal:signal,axios:axios})})};function posts(_a){return __awaiter(this,arguments,void 0,function*({url:url,signal:signal,axios:axios}){var _b;try{const data=null===(_b=(yield axios.get(url,{signal:signal,headers:{Referer:"https://animetsu.to/"}})).data)||void 0===_b?void 0:_b.results,catalog=[];return null==data||data.map(element=>{var _a,_b,_c,_d,_e,_f,_g;const title=(null===(_a=element.title)||void 0===_a?void 0:_a.english)||(null===(_b=element.title)||void 0===_b?void 0:_b.romaji)||(null===(_c=element.title)||void 0===_c?void 0:_c.native),link=null===(_d=element.id)||void 0===_d?void 0:_d.toString(),image=(null===(_e=element.coverImage)||void 0===_e?void 0:_e.large)||(null===(_f=element.coverImage)||void 0===_f?void 0:_f.extraLarge)||(null===(_g=element.coverImage)||void 0===_g?void 0:_g.medium);title&&link&&image&&catalog.push({title:title,link:link,image:image})}),catalog}catch(err){return[]}})}exports.getSearchPosts=getSearchPosts;
|
||||||
1
dist/animetsu/stream.js
vendored
Normal file
1
dist/animetsu/stream.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";var __awaiter=this&&this.__awaiter||function(thisArg,_arguments,P,generator){return new(P||(P=Promise))(function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator.throw(value))}catch(e){reject(e)}}function step(result){var value;result.done?resolve(result.value):(value=result.value,value instanceof P?value:new P(function(resolve){resolve(value)})).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.getStream=void 0;const getStream=function(_a){return __awaiter(this,arguments,void 0,function*({link:id,providerContext:providerContext}){try{const{axios:axios}=providerContext,baseUrl="https://backend.animetsu.to",[animeId,episodeNumber]=id.split(":");if(!animeId||!episodeNumber)throw new Error("Invalid link format");const servers=["pahe","zoro"],streamLinks=[];return yield Promise.all(servers.map(server=>__awaiter(this,void 0,void 0,function*(){try{const url=`${baseUrl}/api/anime/tiddies?server=${server}&id=${animeId}&num=${episodeNumber}&subType=sub`,res=yield axios.get(url,{headers:{Referer:"https://animetsu.to/"}});res.data&&res.data.sources&&res.data.sources.forEach(source=>{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:[]})})}catch(e){}}))),yield Promise.all(servers.map(server=>__awaiter(this,void 0,void 0,function*(){try{const url=`${baseUrl}/api/anime/tiddies?server=${server}&id=${animeId}&num=${episodeNumber}&subType=dub`,res=yield axios.get(url,{headers:{Referer:"https://animetsu.to/"}});res.data&&res.data.sources&&res.data.sources.forEach(source=>{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){}}))),streamLinks}catch(err){return[]}})};exports.getStream=getStream;
|
||||||
24
providers/animetsu/catalog.ts
Normal file
24
providers/animetsu/catalog.ts
Normal 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
109
providers/animetsu/meta.ts
Normal 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: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
90
providers/animetsu/posts.ts
Normal file
90
providers/animetsu/posts.ts
Normal 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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
94
providers/animetsu/stream.ts
Normal file
94
providers/animetsu/stream.ts
Normal 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 [];
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user