mirror of
https://github.com/mdtahseen7/AnimepaheApi.git
synced 2026-04-17 16:11:44 +00:00
Improve API error handling and refresh README response examples
This commit is contained in:
42
README.md
42
README.md
@@ -74,7 +74,7 @@ Output:
|
||||
---
|
||||
|
||||
```http
|
||||
GET /episodes?session=27a95751-0311-47ed-dbce-7f0680d5074a
|
||||
GET /episodes?session=77bbe16e-fd87-13d9-a18c-4edb06884a33
|
||||
```
|
||||
|
||||
Output:
|
||||
@@ -82,18 +82,18 @@ Output:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 70730,
|
||||
"id": 15779,
|
||||
"number": 1,
|
||||
"title": "Episode 1",
|
||||
"snapshot": "https://i.animepahe.si/uploads/snapshots/22c034f704a286b5ce17cc33a3dccf9258cc83038e5bafbcc5a196b2584c3454.jpg",
|
||||
"session": "800a1f7d29d6ebb94d2bfd320b2001b95d00decff4aaecaa6fbef5916379a762"
|
||||
"snapshot": "https://i.animepahe.com/snapshots/6693c23144b7f3d2bc73242740527ea77baa1d2649180bdb63f35b6a0ef9188b.jpg",
|
||||
"session": "18ea551da39ccf31e77f9702365193b45636c5ffe7168f209830a56607f2a9d3"
|
||||
},
|
||||
{
|
||||
"id": 70823,
|
||||
"id": 15780,
|
||||
"number": 2,
|
||||
"title": "Episode 2",
|
||||
"snapshot": "https://i.animepahe.si/uploads/snapshots/baf28a9ea1fecf9bbee49844cf3b782632e487ff49d3ba5c93b56241719fab05.jpg",
|
||||
"session": "4dd535ded2d2773bb3285881839d018c5787619de262dffb801ab4f78cf20123"
|
||||
"snapshot": "https://i.animepahe.com/snapshots/44025fa8399d9d68584903c2b5b23c579fd1d73f33570d2d95e783895d97f757.jpg",
|
||||
"session": "38517b2d536b4c2a2c0c082f1995eb26b04c8af98889afebdb26f344a33c324b"
|
||||
}
|
||||
]
|
||||
```
|
||||
@@ -101,7 +101,7 @@ Output:
|
||||
---
|
||||
|
||||
```http
|
||||
GET /sources?anime_session=27a95751-0311-47ed-dbce-7f0680d5074a&episode_session=800a1f7d29d6ebb94d2bfd320b2001b95d00decff4aaecaa6fbef5916379a762
|
||||
GET /sources?anime_session=77bbe16e-fd87-13d9-a18c-4edb06884a33&episode_session=18ea551da39ccf31e77f9702365193b45636c5ffe7168f209830a56607f2a9d3
|
||||
```
|
||||
|
||||
Output:
|
||||
@@ -109,21 +109,15 @@ Output:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"url": "https://kwik.si/e/KcfYGhr86Ww2",
|
||||
"quality": "1080p",
|
||||
"fansub": "KawaSubs",
|
||||
"url": "https://kwik.cx/e/4q3V1NDdRVy9",
|
||||
"quality": "800p",
|
||||
"fansub": "df68",
|
||||
"audio": "jpn"
|
||||
},
|
||||
{
|
||||
"url": "https://kwik.si/e/Sr2gRRoVz6wy",
|
||||
"quality": "720p",
|
||||
"fansub": "KawaSubs",
|
||||
"audio": "jpn"
|
||||
},
|
||||
{
|
||||
"url": "https://kwik.si/e/J7jBHBSJhTEv",
|
||||
"url": "https://kwik.cx/e/GDFF1EyEUCLD",
|
||||
"quality": "360p",
|
||||
"fansub": "KawaSubs",
|
||||
"fansub": "df68",
|
||||
"audio": "jpn"
|
||||
}
|
||||
]
|
||||
@@ -132,14 +126,20 @@ Output:
|
||||
---
|
||||
|
||||
```http
|
||||
GET /m3u8?url=https://kwik.si/e/uEPQKLMzFpaz
|
||||
GET /m3u8?url=https://kwik.cx/e/4q3V1NDdRVy9
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{
|
||||
"m3u8": "https://vault-12.owocdn.top/stream/12/12/1478df0e98f767de547ac36d33bc92b73b9a5b7318fe3f3e81328fa31fc1eac3/uwu.m3u8"
|
||||
"m3u8": "https://vault-01.uwucdn.top/stream/01/03/b92a392054c041a3f9c6eecabeb0e127183f44e547828447b10bca8d77523e6f/uwu.m3u8",
|
||||
"referer": "https://kwik.cx/e/4q3V1NDdRVy9",
|
||||
"headers": {
|
||||
"Referer": "https://kwik.cx/e/4q3V1NDdRVy9",
|
||||
"Origin": "https://kwik.cx"
|
||||
},
|
||||
"proxy_url": "/proxy?url=https%3A%2F%2Fvault-01.uwucdn.top%2Fstream%2F01%2F03%2Fb92a392054c041a3f9c6eecabeb0e127183f44e547828447b10bca8d77523e6f%2Fuwu.m3u8&referer=https%3A%2F%2Fkwik.cx%2Fe%2F4q3V1NDdRVy9"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
18
index.js
18
index.js
@@ -15,6 +15,14 @@ app.use(express.static('public'));
|
||||
// Create AnimePahe instance
|
||||
const pahe = new AnimePahe();
|
||||
|
||||
function mapErrorToStatusCode(message) {
|
||||
const text = String(message || '').toLowerCase();
|
||||
if (text.includes('not found')) return 404;
|
||||
if (text.includes('blocked') || text.includes('anti-bot')) return 503;
|
||||
if (text.includes('forbidden')) return 403;
|
||||
return 500;
|
||||
}
|
||||
|
||||
// Routes
|
||||
app.get('/', (req, res) => {
|
||||
res.json({
|
||||
@@ -51,7 +59,7 @@ app.get('/search', async (req, res) => {
|
||||
res.json(results);
|
||||
} catch (error) {
|
||||
console.error('Search error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
res.status(mapErrorToStatusCode(error.message)).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -65,7 +73,7 @@ app.get('/episodes', async (req, res) => {
|
||||
res.json(episodes);
|
||||
} catch (error) {
|
||||
console.error('Episodes error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
res.status(mapErrorToStatusCode(error.message)).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -81,7 +89,7 @@ app.get('/sources', async (req, res) => {
|
||||
res.json(sources);
|
||||
} catch (error) {
|
||||
console.error('Sources error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
res.status(mapErrorToStatusCode(error.message)).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,7 +103,7 @@ app.get('/ids', async (req, res) => {
|
||||
res.json(ids);
|
||||
} catch (error) {
|
||||
console.error('IDs error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
res.status(mapErrorToStatusCode(error.message)).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -119,7 +127,7 @@ app.get('/m3u8', async (req, res) => {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('M3U8 resolution error:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
res.status(mapErrorToStatusCode(error.message)).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -104,6 +104,54 @@ class AnimePahe {
|
||||
return animeSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert noisy upstream errors into concise API-safe messages
|
||||
* @param {string} context - Operation context (search, episodes, etc)
|
||||
* @param {Error|any} error - Raw error
|
||||
* @returns {string} Public error message
|
||||
* @private
|
||||
*/
|
||||
_formatUpstreamError(context, error) {
|
||||
const rawMessage = String(error?.message || error || 'Unknown error');
|
||||
const statusMatch = rawMessage.match(/^(\d{3})\s*-\s*/);
|
||||
const statusCode = statusMatch ? parseInt(statusMatch[1], 10) : null;
|
||||
|
||||
if (statusCode === 404 || /Oops\.\.\.\s*404|404\s+Not\s+Found/i.test(rawMessage)) {
|
||||
if (context === 'episodes') {
|
||||
return 'Anime session not found. Use /search first to get a valid session id.';
|
||||
}
|
||||
if (context === 'sources') {
|
||||
return 'Anime or episode session not found. Use /episodes first to get a valid episode_session.';
|
||||
}
|
||||
if (context === 'ids') {
|
||||
return 'Anime session not found. Use /search first to get a valid session id.';
|
||||
}
|
||||
}
|
||||
|
||||
if (statusCode === 403 && /ddos-guard|checking your browser|cloudflare/i.test(rawMessage)) {
|
||||
return 'Upstream blocked the request (anti-bot challenge). Please retry shortly.';
|
||||
}
|
||||
|
||||
let cleaned = rawMessage
|
||||
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
||||
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/^\d{3}\s*-\s*"?/, '')
|
||||
.replace(/"$/, '')
|
||||
.trim();
|
||||
|
||||
if (!cleaned) {
|
||||
cleaned = 'Unexpected upstream error';
|
||||
}
|
||||
|
||||
if (cleaned.length > 220) {
|
||||
cleaned = `${cleaned.slice(0, 220)}...`;
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for anime by query
|
||||
* @param {string} query - Search query
|
||||
@@ -138,7 +186,7 @@ class AnimePahe {
|
||||
|
||||
return results;
|
||||
} catch (error) {
|
||||
throw new Error(`Search failed: ${error.message}`);
|
||||
throw new Error(`Search failed: ${this._formatUpstreamError('search', error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +256,7 @@ class AnimePahe {
|
||||
|
||||
return formattedEpisodes;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to get episodes: ${error.message}`);
|
||||
throw new Error(`Failed to get episodes: ${this._formatUpstreamError('episodes', error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +336,7 @@ class AnimePahe {
|
||||
|
||||
return uniqueSources;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to get sources: ${error.message}`);
|
||||
throw new Error(`Failed to get sources: ${this._formatUpstreamError('sources', error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +442,7 @@ ${transformedScript}
|
||||
|
||||
throw new Error(`Could not resolve .m3u8. Node output (first 2000 chars):\n${nodeOutput.substring(0, 2000)}`);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to resolve Kwik URL: ${error.message}`);
|
||||
throw new Error(`Failed to resolve Kwik URL: ${this._formatUpstreamError('m3u8', error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +467,7 @@ ${transformedScript}
|
||||
myanimelist: malId ? parseInt(malId, 10) : null
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to get IDs: ${error.message}`);
|
||||
throw new Error(`Failed to get IDs: ${this._formatUpstreamError('ids', error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user