The streaming endpoints (/episodes, /sources, /stream, /watch, /download)
returned 500 because the upstream Miruro pipe changed and www.miruro.tv is
now hard-blocked by Cloudflare.
Reverse-engineered the current Miruro frontend contract:
- Request is plain base64url of the JSON payload (no XOR).
- Response obfuscation is now signalled by the x-obfuscated header:
absent = plain JSON, 1 = base64+gzip, 2 = base64+XOR(PIPE_OBF_KEY)+gzip.
pipe.js now:
- rotates across mirrors (miruro.ru > .to > .bz > .tv), one per retry;
- decodes based on the x-obfuscated header instead of always XOR+gunzip;
- sends full browser sec-fetch/sec-ch-ua headers to pass Cloudflare checks;
- raises maxRetries to 4 and rotates on 403/444.
proxy.js default referer/Origin -> https://www.miruro.to (miruro.tv is dead).
AniList-backed endpoints were already healthy and are unaffected.
Version bumped to 2.2.0 across package.json, server.js, /api/health,
/api/openapi, public/openapi.json. CHANGELOG updated.
- Move XOR keys to env vars (PRU_PROXY_KEY, PIPE_OBF_KEY)
- Fix multi-search to combine query + filters
- Fix deepTranslate to return clone instead of mutating
- Improve getBestStream quality matching and fallback
- Add input sanitization for all route params
- CORS blocks unknown origins in production
- Security headers in vercel.json at CDN level
- stats/genre uses Promise.allSettled for parallel execution
- Delete dead server.py, fix version strings
Root cause: createApiRoutes() parameter shift
- Function signature was (app, jsonResponse, jsonError)
- Called from server.js as apiRoutes(jsonResponse, jsonError)
- All params shifted: jsonResponse→jsonError, jsonError→undefined
- Every success response returned {success: false, message: data}
- Health worked because it used res.json() directly
Fix: Removed unused 'app' parameter from createApiRoutes()
All 18 endpoints now return {success: true, results: data}
- 16 API endpoints powered by AniList GraphQL
- Miruro pipe integration for streaming sources
- 12 streaming providers (kiwi, pewe, bee, bonk, etc.)
- M3U8 streaming URLs with subtitles and skip timestamps
- In-memory caching with TTL
- CORS support and health endpoint