This commit is contained in:
shafat420
2025-06-05 21:43:19 +06:00
parent 60091b7a21
commit 63ac812298

649
index.js
View File

@@ -1,322 +1,327 @@
const express = require('express'); const express = require('express');
const axios = require('axios'); const axios = require('axios');
const cors = require('cors'); const cors = require('cors');
const { mapAniListToAnicrush, getCommonHeaders } = require('./mapper'); const { mapAniListToAnicrush, getCommonHeaders } = require('./mapper');
const { getHlsLink } = require('./hls'); const { getHlsLink } = require('./hls');
require('dotenv').config(); require('dotenv').config();
const app = express(); const app = express();
// Remove explicit port for Vercel // Remove explicit port for Vercel
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
// CORS configuration for Vercel // CORS configuration for Vercel
app.use(cors({ app.use(cors({
origin: '*', origin: '*',
methods: ['GET', 'POST', 'OPTIONS'], methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'] allowedHeaders: ['Content-Type', 'Authorization']
})); }));
app.use(express.json()); app.use(express.json());
// Endpoint to map AniList ID to anicrush // Endpoint to map AniList ID to anicrush
app.get('/api/mapper/:anilistId', async (req, res) => { app.get('/api/mapper/:anilistId', async (req, res) => {
try { try {
const { anilistId } = req.params; const { anilistId } = req.params;
if (!anilistId) { if (!anilistId) {
return res.status(400).json({ error: 'AniList ID is required' }); return res.status(400).json({ error: 'AniList ID is required' });
} }
const mappedData = await mapAniListToAnicrush(anilistId); const mappedData = await mapAniListToAnicrush(anilistId);
res.json(mappedData); res.json(mappedData);
} catch (error) { } catch (error) {
console.error('Error in mapper:', error); console.error('Error in mapper:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to map AniList ID', error: 'Failed to map AniList ID',
message: error.message message: error.message
}); });
} }
}); });
// Endpoint to search for anime // Endpoint to search for anime
app.get('/api/anime/search', async (req, res) => { app.get('/api/anime/search', async (req, res) => {
try { try {
const { keyword, page = 1, limit = 24 } = req.query; const { keyword, page = 1, limit = 24 } = req.query;
if (!keyword) { if (!keyword) {
return res.status(400).json({ error: 'Search keyword is required' }); return res.status(400).json({ error: 'Search keyword is required' });
} }
const headers = getCommonHeaders(); const headers = getCommonHeaders();
const response = await axios({ const response = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/movie/list`, url: `https://api.anicrush.to/shared/v2/movie/list`,
params: { params: {
keyword, keyword,
page, page,
limit limit
}, },
headers headers
}); });
res.json(response.data); res.json(response.data);
} catch (error) { } catch (error) {
console.error('Error searching anime:', error); console.error('Error searching anime:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to search anime', error: 'Failed to search anime',
message: error.message message: error.message
}); });
} }
}); });
// Endpoint to fetch episode list // Endpoint to fetch episode list
app.get('/api/anime/episodes', async (req, res) => { app.get('/api/anime/episodes', async (req, res) => {
try { try {
const { movieId } = req.query; const { movieId } = req.query;
if (!movieId) { if (!movieId) {
return res.status(400).json({ error: 'Movie ID is required' }); return res.status(400).json({ error: 'Movie ID is required' });
} }
const headers = getCommonHeaders(); const headers = getCommonHeaders();
const response = await axios({ const response = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/list`, url: `https://api.anicrush.to/shared/v2/episode/list`,
params: { params: {
_movieId: movieId _movieId: movieId
}, },
headers headers
}); });
res.json(response.data); res.json(response.data);
} catch (error) { } catch (error) {
console.error('Error fetching episode list:', error); console.error('Error fetching episode list:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to fetch episode list', error: 'Failed to fetch episode list',
message: error.message message: error.message
}); });
} }
}); });
// Endpoint to fetch servers for an episode // Endpoint to fetch servers for an episode
app.get('/api/anime/servers/:movieId', async (req, res) => { app.get('/api/anime/servers/:movieId', async (req, res) => {
try { try {
const { movieId } = req.params; const { movieId } = req.params;
const { episode } = req.query; const { episode } = req.query;
if (!movieId) { if (!movieId) {
return res.status(400).json({ error: 'Movie ID is required' }); return res.status(400).json({ error: 'Movie ID is required' });
} }
const headers = getCommonHeaders(); const headers = getCommonHeaders();
const response = await axios({ const response = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/servers`, url: `https://api.anicrush.to/shared/v2/episode/servers`,
params: { params: {
_movieId: movieId, _movieId: movieId,
ep: episode || 1 ep: episode || 1
}, },
headers headers
}); });
res.json(response.data); res.json(response.data);
} catch (error) { } catch (error) {
console.error('Error fetching servers:', error); console.error('Error fetching servers:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to fetch servers', error: 'Failed to fetch servers',
message: error.message message: error.message
}); });
} }
}); });
// Main endpoint to fetch anime sources // Main endpoint to fetch anime sources
app.get('/api/anime/sources', async (req, res) => { app.get('/api/anime/sources', async (req, res) => {
try { try {
const { movieId, episode, server, subOrDub } = req.query; const { movieId, episode, server, subOrDub } = req.query;
if (!movieId) { if (!movieId) {
return res.status(400).json({ error: 'Movie ID is required' }); return res.status(400).json({ error: 'Movie ID is required' });
} }
const headers = getCommonHeaders(); const headers = getCommonHeaders();
// First, check if the episode list exists // First, check if the episode list exists
const episodeListResponse = await axios({ const episodeListResponse = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/list`, url: `https://api.anicrush.to/shared/v2/episode/list`,
params: { params: {
_movieId: movieId _movieId: movieId
}, },
headers headers
}); });
if (!episodeListResponse.data || episodeListResponse.data.status === false) { if (!episodeListResponse.data || episodeListResponse.data.status === false) {
return res.status(404).json({ error: 'Episode list not found' }); return res.status(404).json({ error: 'Episode list not found' });
} }
// Then, get the servers for the episode // Then, get the servers for the episode
const serversResponse = await axios({ const serversResponse = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/servers`, url: `https://api.anicrush.to/shared/v2/episode/servers`,
params: { params: {
_movieId: movieId, _movieId: movieId,
ep: episode || 1 ep: episode || 1
}, },
headers headers
}); });
if (!serversResponse.data || serversResponse.data.status === false) { if (!serversResponse.data || serversResponse.data.status === false) {
return res.status(404).json({ error: 'Servers not found' }); return res.status(404).json({ error: 'Servers not found' });
} }
// Finally, get the sources // Finally, get the sources
const sourcesResponse = await axios({ const sourcesResponse = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/sources`, url: `https://api.anicrush.to/shared/v2/episode/sources`,
params: { params: {
_movieId: movieId, _movieId: movieId,
ep: episode || 1, ep: episode || 1,
sv: server || 4, sv: server || 4,
sc: subOrDub || 'sub' sc: subOrDub || 'sub'
}, },
headers headers
}); });
res.json(sourcesResponse.data); res.json(sourcesResponse.data);
} catch (error) { } catch (error) {
console.error('Error fetching anime sources:', error); console.error('Error fetching anime sources:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to fetch anime sources', error: 'Failed to fetch anime sources',
message: error.message message: error.message
}); });
} }
}); });
// Endpoint to get HLS link // Endpoint to get HLS link
app.get('/api/anime/hls/:movieId', async (req, res) => { app.get('/api/anime/hls/:movieId', async (req, res) => {
try { try {
const { movieId } = req.params; const { movieId } = req.params;
const { episode = 1, server = 4, subOrDub = 'sub' } = req.query; const { episode = 1, server = 4, subOrDub = 'sub' } = req.query;
if (!movieId) { if (!movieId) {
return res.status(400).json({ error: 'Movie ID is required' }); return res.status(400).json({ error: 'Movie ID is required' });
} }
const headers = getCommonHeaders(); const headers = getCommonHeaders();
// First get the embed link // First get the embed link
const embedResponse = await axios({ const embedResponse = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/sources`, url: `https://api.anicrush.to/shared/v2/episode/sources`,
params: { params: {
_movieId: movieId, _movieId: movieId,
ep: episode, ep: episode,
sv: server, sv: server,
sc: subOrDub sc: subOrDub
}, },
headers headers
}); });
if (!embedResponse.data || embedResponse.data.status === false) { if (!embedResponse.data || embedResponse.data.status === false) {
return res.status(404).json({ error: 'Embed link not found' }); return res.status(404).json({ error: 'Embed link not found' });
} }
const embedUrl = embedResponse.data.result.link; const embedUrl = embedResponse.data.result.link;
// Get HLS link from embed URL // Get HLS link from embed URL
const hlsData = await getHlsLink(embedUrl); const hlsData = await getHlsLink(embedUrl);
res.json(hlsData); res.json(hlsData);
} catch (error) { } catch (error) {
console.error('Error fetching HLS link:', error); console.error('Error fetching HLS link:', error);
res.status(500).json({ res.status(500).json({
error: 'Failed to fetch HLS link', error: 'Failed to fetch HLS link',
message: error.message message: error.message
}); });
} }
}); });
// Combined endpoint to get HLS link directly from AniList ID // Combined endpoint to get HLS link directly from AniList ID
app.get('/api/anime/:anilistId/:episodeNum', async (req, res) => { app.get('/api/anime/:anilistId/:episodeNum', async (req, res) => {
try { try {
const { anilistId, episodeNum } = req.params; const { anilistId, episodeNum } = req.params;
const { server = 4, subOrDub = 'sub' } = req.query; const { server = 4, subOrDub = 'sub' } = req.query;
if (!anilistId) { if (!anilistId) {
return res.status(400).json({ error: 'AniList ID is required' }); return res.status(400).json({ error: 'AniList ID is required' });
} }
// First map AniList ID to Anicrush ID // First map AniList ID to Anicrush ID
const mappedData = await mapAniListToAnicrush(anilistId); const mappedData = await mapAniListToAnicrush(anilistId);
if (!mappedData || !mappedData.anicrush_id) { if (!mappedData || !mappedData.anicrush_id) {
return res.status(404).json({ error: 'Anime not found on Anicrush' }); return res.status(404).json({ error: 'Anime not found on Anicrush' });
} }
const movieId = mappedData.anicrush_id; const movieId = mappedData.anicrush_id;
const headers = getCommonHeaders(); const headers = getCommonHeaders();
// Get the embed link // Get the embed link
const embedResponse = await axios({ const embedResponse = await axios({
method: 'GET', method: 'GET',
url: `https://api.anicrush.to/shared/v2/episode/sources`, url: `https://api.anicrush.to/shared/v2/episode/sources`,
params: { params: {
_movieId: movieId, _movieId: movieId,
ep: episodeNum || 1, ep: episodeNum || 1,
sv: server, sv: server,
sc: subOrDub sc: subOrDub
}, },
headers headers
}); });
if (!embedResponse.data || embedResponse.data.status === false) { if (!embedResponse.data || embedResponse.data.status === false) {
return res.status(404).json({ error: 'Embed link not found' }); return res.status(404).json({ error: 'Embed link not found' });
} }
const embedUrl = embedResponse.data.result.link; const embedUrl = embedResponse.data.result.link;
// Get HLS link from embed URL // Get HLS link from embed URL
const hlsData = await getHlsLink(embedUrl); const hlsData = await getHlsLink(embedUrl);
// Add metadata from the mapped data // Find the specific episode data
const response = { const episodeNumber = parseInt(episodeNum) || 1;
...hlsData, const episodeData = mappedData.episodes.find(ep => ep.number === episodeNumber) || {};
metadata: {
title: mappedData.titles?.english || mappedData.titles?.romaji, // Add metadata from the mapped data
anilistId: parseInt(anilistId), const response = {
movieId: movieId, ...hlsData,
episode: parseInt(episodeNum) || 1, metadata: {
server: parseInt(server) || 4, title: mappedData.titles?.english || mappedData.titles?.romaji,
subOrDub: subOrDub || 'sub' anilistId: parseInt(anilistId),
} movieId: movieId,
}; episode: episodeNumber,
server: parseInt(server) || 4,
res.json(response); subOrDub: subOrDub || 'sub',
image: episodeData.image || null
} catch (error) { }
console.error('Error fetching anime stream:', error); };
res.status(500).json({
error: 'Failed to fetch anime stream', res.json(response);
message: error.message
}); } catch (error) {
} console.error('Error fetching anime stream:', error);
}); res.status(500).json({
error: 'Failed to fetch anime stream',
// Health check endpoint message: error.message
app.get('/health', (req, res) => { });
res.json({ status: 'OK' }); }
}); });
// Only start the server if not in Vercel environment // Health check endpoint
if (process.env.VERCEL !== '1') { app.get('/health', (req, res) => {
app.listen(PORT, () => { res.json({ status: 'OK' });
console.log(`Server is running on port ${PORT}`); });
});
} // Only start the server if not in Vercel environment
if (process.env.VERCEL !== '1') {
// Export the Express app for Vercel app.listen(PORT, () => {
module.exports = app; console.log(`Server is running on port ${PORT}`);
});
}
// Export the Express app for Vercel
module.exports = app;