# Changelog ## v2.3.2 ### Cloudflare Worker Implementation — Issue #2 Fix #### New: `worker.js` (Cloudflare Worker Edge Runtime) - **Full Cloudflare Worker implementation** created at project root - Edge-to-edge requests bypass Cloudflare bot detection (Worker → miruro.to → Cloudflare trusts itself) - Zero cold starts, 100K free requests/day on Cloudflare free tier - No npm dependencies — uses native `fetch`, `DecompressionStream`, `TextEncoder`/`TextDecoder` - 15 API endpoints: search, suggestions, filter, trending, trending/daily, trending/weekly, popular, top, upcoming, recent, random, info, episodes, watch, stream, genres, tags, providers, health #### New: `wrangler.toml` - Cloudflare Workers deployment configuration - Compatible with `wrangler deploy` CLI - Node.js compatibility flag enabled for buffer/text encoding support - CPU time limit: 30 seconds #### Architecture ``` Browser → Cloudflare Worker (edge) → miruro.to pipe → Cloudflare trusts itself ✅ Vercel (datacenter) → miruro.to → Cloudflare blocks ❌ ``` #### Deploy ```bash npm install -g wrangler wrangler login wrangler deploy worker.js --name miruroapi ``` #### Files Changed - `worker.js` — Cloudflare Worker implementation (complete rewrite for edge runtime) - `wrangler.toml` — Cloudflare Workers deployment configuration - `CHANGELOG.md` — This entry #### Notes - This fixes Issue #2: Cloudflare Worker/Pages deployment support - Streaming endpoints (`/episodes`, `/watch`, `/stream`) now work via edge-to-edge requests - Environment variables `SCRAPER_API_KEY` and `FLARESOLVERR_URL` are optional for fallback methods - The worker runs on Cloudflare's edge network with zero cold starts --- ## v2.3.1 ### Cloudflare Worker Edition — Streaming Bypasses Cloudflare #### New: `worker.js` (Cloudflare Worker) - Full API running on Cloudflare's edge network - **Streaming endpoints work** — edge-to-edge requests bypass bot detection - Zero cold starts, 100K free requests/day - No npm dependencies (native `fetch` + `DecompressionStream`) - 15 endpoints: search, trending, info, episodes, watch, genres, random #### Why Workers Work ``` Vercel (datacenter) → miruro.to → Cloudflare blocks ❌ Worker (edge) → miruro.to → Cloudflare trusts itself ✅ ``` #### Deploy ```bash npm install -g wrangler wrangler login wrangler deploy worker.js --name miruroapi ``` #### Files Changed - `worker.js` — Cloudflare Worker implementation (885 lines) - `README.md` — Added Worker deployment section, updated troubleshooting - `docs/architecture.md` — Added Worker architecture section --- ## v2.3.0 ### Self-Healing Fallback System — Auto-Recovery from Cloudflare Blocks #### New: Multi-Method Fallback System Pipe requests now try **3 methods in order** with automatic fallback: 1. **Direct** — mirror rotation across `.ru` → `.to` → `.bz` → `.tv` with browser headers 2. **ScraperAPI** — proxy through `api.scraperapi.com` (free 1,000 req/month, no CC) 3. **FlareSolverr** — self-hosted browser proxy that solves Cloudflare Turnstile When one method fails (403/timeout), the next is tried automatically. No manual intervention needed. #### New Endpoint: `/api/pipe-health` Diagnostic endpoint that tests all configured methods and reports: - Which methods are working/failed - Latency for each method - Recommendation on preferred method ``` GET /api/pipe-health → { methods: { direct: {status:"ok"}, scraperapi: {status:"skipped"} }, working: 1, ... } ``` #### Configuration (all optional, zero-config to start) | Env Var | Purpose | Free? | |---------|---------|-------| | `SCRAPER_API_KEY` | ScraperAPI proxy | No ($49/mo premium required for protected domains) | | `FLARESOLVERR_URL` | FlareSolverr browser | Yes (self-hosted) | | `PIPE_OBF_KEY` | XOR decode key | N/A | #### How it works ``` Client → /api/episodes/20 ↓ pipeRequest() ├─ Try direct → 403 (Cloudflare block) ├─ Try ScraperAPI → 200 ✓ (returns data) └─ Cache result, return to client ``` #### Files Changed - `src/helpers/pipe.js` — rewritten with `methodDirect()`, `methodScraperAPI()`, `methodFlareSolverr()`, `pipeHealthCheck()` - `src/routes/apiRoutes.js` — added `/api/pipe-health` endpoint - `.env.example` — documented `SCRAPER_API_KEY`, `FLARESOLVERR_URL` #### Notes - Zero-config: works without any env vars (direct only) - Add `SCRAPER_API_KEY` for free Cloudflare bypass (no server needed) - Add `FLARESOLVERR_URL` for self-hosted browser bypass (needs Docker/VPS) - All methods use the same pipe protocol (base64+gzip, x-obfuscated header) ## v2.2.0 ### Critical Fix — Miruro Pipe Protocol Migration (Streaming Endpoints Restored) #### Diagnostic Summary - **Full diagnostic sweep** of all live `/api/*` endpoints against `mirurotvapi.vercel.app` - **AniList-backed endpoints** (`/search`, `/trending`, `/info`, `/popular`, `/top`, …) — confirmed **all 200/healthy** - **Streaming endpoints** (`/episodes`, `/sources`, `/stream`, `/watch`, `/download`) — **all 500** - Deep-scanned the Miruro frontend (`miruro.to/.bz/.ru`) bundles + `env2.js` to reverse-engineer the new pipe contract #### Root Cause (streaming failure) 1. **Dead data source** — `pipe.js` targeted `https://www.miruro.tv/api/secure/pipe`, which is now hard-blocked by Cloudflare (returns 403 "Sorry, you have been blocked" page). 2. **Stale decode protocol** — the old `decode()` always did `base64url → XOR(PIPE_OBF_KEY) → gunzip`. Miruro's pipe now **signals the scheme via a response header**: - `x-obfuscated` absent → plain JSON - `x-obfuscated: 1` → `base64url(gzip(json))` (**no XOR**) - `x-obfuscated: 2` → `base64url(XOR(gzip(json)))` with `PIPE_OBF_KEY` - The hard-coded always-XOR decode corrupted the new `:1` payloads. #### Fixes - **`src/helpers/pipe.js`** - New **mirror rotation** list: `miruro.ru` → `miruro.to` → `miruro.bz` → `miruro.tv`, iterating one mirror per retry. - **New header-driven `decodePipeResponse(text, obfHeader)`** supporting plain / scheme-1 / scheme-2. - **Browser-accurate request headers** (UA + `Accept`, `Accept-Language`, full `sec-ch-ua` / `sec-fetch-*` family) to pass Cloudflare bot fingerprinting rather than just UA+Referer. - Request payload reverted to **plain base64url of the JSON** (no XOR on the request) matching the current client. - Subtitle-proxy referer updated to canonical `https://www.miruro.to/`. - Default `maxRetries` bumped 3 → 4 so each mirror gets an attempt; 403/444 now rotate instead of failing. - **`api/proxy.js`** — default CDN referer/Origin switched from the dead `miruro.tv` to the canonical `miruro.to`. - **Version bump** to `2.2.0` across `package.json`, `server.js` banner, `/api/health`, `/api/openapi`, and `public/openapi.json`. #### Notes - Streaming endpoints depend on Miruro's upstream pipe, which sits behind Cloudflare bot protection and may intermittently rate-limit datacenter egress IPs. The new rotation + browser headers + retry logic maximizes success; AniList endpoints are unaffected and remain fully healthy. ## v2.1.4 ### Security Hardening, Bug Fixes, Code Quality Improvements #### Security - **XOR keys moved to env vars** — `PRU_PROXY_KEY` and `PIPE_OBF_KEY` no longer hardcoded in source (proxy.js, pipe.js) - **CORS restricted in production** — returns 403 when `ALLOWED_ORIGINS` is set and origin doesn't match - **Input sanitization** — new `sanitizeId()` and `sanitizeString()` helpers applied to all route params (character, staff, studio, genre, year, status, format, season) - **Security headers in vercel.json** — added at CDN level for faster response #### Bug Fixes - **multi-search** — now actually combines query + filters (was ignoring `q` when filters present) - **`filterAnime`** — added `search` parameter and `SEARCH_MATCH` sort option - **`getTrendingWeekly`** — now returns 40 results (was identical to daily with 20) - **`calendar`** — fetches 200 results instead of 50 (was missing late-month shows) - **`getBestStream`** — improved quality matching (checks quality/label fields), supports HLS+DASH, better fallback - **`deepTranslate`** — now returns deep clone instead of mutating in-place (prevents cache corruption) - **Version strings** — updated to 2.1.3 in server.js and test.js #### Code Quality - **Deleted `server.py`** — dead Flask code, not used on Vercel - **Rate limiter** — aggressive cleanup on serverless (prunes empty entries every request) - **`stats/genre`** — uses `Promise.allSettled` for parallel execution (faster, safer) #### Config - **vercel.json** — added security headers at CDN level - **.env.example** — added `PRU_PROXY_KEY`, `PIPE_OBF_KEY` documentation ## v2.1.3 ### Diagnostic Sweep — Bug fixes, security, AniList query corrections #### Full Diagnostic Sweep Results - Tested all 44 endpoints across 10 sections - Found and fixed 5 bugs - Added missing security headers #### Bug Fixes - **Tags endpoint**: `data.TagCollection` → `data.MediaTagCollection` (was returning empty array) - **Random endpoint**: Added `Cache-Control: no-store` headers + `Date.now() % 499` for true randomness (CDN was caching rapid requests) - **Character/Staff 404**: Now returns HTTP 404 instead of 500 on not-found - **Character query**: Removed `dateOfDeath` (not in AniList schema), `role` → `characterRole` - **Staff query**: Removed `dateOfDeath` and invalid `role` field - **Studio query**: Removed `type: ANIME` from `Studio.media` (not supported by AniList) - **Tags query**: `TagCollection` → `MediaTagCollection`, removed `rank` field - **Trending**: Removed invalid `trending: 7/30` args (not in AniList schema) #### Security - Added `X-XSS-Protection: 1; mode=block` header #### Pipe Resilience - Added `pipeRequest()` helper with retry logic and exponential backoff (3 attempts: 1s, 2s, 4s delays) - Cached episodes (5 min) and sources (10 min) responses - Confirmed kiwi/bonk CDNs serve real content, bee/ally serve decoys - Fixed `getWatchSources` slug matching for both raw and slugged episode IDs #### Performance - Fastest: `/providers` ~0.8s (static data) - Average: Most endpoints ~1.0-2.0s - Slowest: `/stats/genre` ~5.7s (10 AniList queries) ## v2.1.2 ### Streaming Architecture — pru proxy + raw CDN URLs #### Streaming Pipeline Discovery - Decoded pru.ultracloud.cc URL format: `base64url(XOR(url, key))~base64url(XOR(referer, key))/pl.m3u8` - Key: `a54d389c18527d9fd3e7f0643e27edbe` (16-byte XOR) - pru rewrites ALL M3U8 URLs (master, variant, segments) to proxy through itself - CDN at mt.nekostream.site serves decoy PNG images to all server-side requests #### Proxy Changes - `/api/proxy` now handles both pru-encoded URLs (decodes + re-encodes) and direct CDN URLs (for subtitles) - Stream URLs returned as raw CDN URLs (browser loads directly — CDN has CORS *) - Subtitle URLs proxied through `/api/proxy` (third-party CDNs may lack CORS) - Added `Origin: https://www.miruro.tv` header to pipe requests #### Known Limitations - Pipe sources endpoint returns 444 from Cloudflare for datacenter IPs - Client-side pipe blocked by CORS (only allows miruro.tv origin) - CDN segments serve PNG decoys to server IPs - Video playback requires further investigation — likely needs miruro.tv domain or alternative streaming source ## v2.1.1 ### Bug Fix — Pipe response XOR decoding #### Fix - `decodePipeResponse` now XOR-decodes with obfuscation key before gzip decompression — pipe was returning XOR+gzip, not plain gzip - Updated pipe version from `0.1.0` to `0.2.0` to match miruro.tv - `getWatchSources` now properly returns streams (was always failing before this fix) ## v2.1.0 ### Major Feature Update — Provider capabilities, enriched metadata, skip times #### New Endpoints - GET /api/providers — Provider capabilities and configuration (12 providers with full metadata) #### Anime Info Enrichment - Added `alternateName` — multiple language titles from synonyms - Added `aggregateRating` — rating with count, mean score - Added `sameAs` — external links (AniList, MAL, official sites) - Added `externalLinks` — structured external links with site/type - Added `productionCompany` — non-animation studios - Added `animationStudio` — animation studios - Added `trailer` — anime trailer info - Added `nextAiringEpisode` — next episode air time - Added `tags` — simplified tag names array #### Streaming Improvements - Added `extractSkipTimes` — extract OP/ED skip timestamps from sources - Added `skipTimes` field to /stream and /watch responses - Episode thumbnails already included in pipe response #### Provider Capabilities (from miruro.tv __SSR_CONFIG__) - kiwi: sub, download - pewe: sub - bonk: sub, ssub, download, skip_times - bee: ssub - ally: sub, download, thumbnails - moo: sub, download - hop: ssub, thumbnails - nun: sub (embed of ally) - bun: ssub (embed of bee) - twin: sub, ssub (embed of bonk) - cog: sub (embed of moo) - telli: sub (embed of kiwi, hidden) --- ## v2.0.1 ### Streaming Improvements — Better subtitle extraction, quality fallback #### Streaming Enhancements - Improved `extractSubtitles` — now handles multiple provider formats (bonk: file/label/kind/language, others: url/name/lang) - Updated `getBestStream` — falls back to first active HLS stream when quality metadata is missing - Updated `getDownloadUrl` — now returns subtitles and bestStream in response - Added subtitle fields: url, label, language, kind, format, encoding, isDefault #### Provider Improvements - Bonk provider confirmed to return subtitles (English, VTT format, captions kind) - Better handling of providers without quality metadata (bonk, ally, bee return undefined quality) #### Verified - Subtitle extraction working: bonk provider returns 1 English subtitle per episode - Download URL working: bonk provider returns direct download link - Batch sources: subtitles included in batch responses --- ## v2.0.0 ### Major Release — 35 endpoints, streaming improvements, new features #### Technical Foundation - Added gzip compression middleware (30-70% response size reduction) - Added request logging with method, path, status, duration, IP - Added Cache-Control headers for API responses (varies by endpoint type) - Improved CORS with preflight caching (24h max-age) - Health endpoint now includes memory stats (heap, RSS), cache size, node version #### New AniList Helpers (11 new functions) - getAllGenres — complete genre list from AniList - getAllTags — complete tag list with metadata - getTopAnime — top-rated anime of all time (SCORE_DESC) - getTrendingDaily — trending anime (last 7 days) - getTrendingWeekly — trending anime (last 30 days) - getSeasonalAnime — anime by year + season (e.g., 2025/Spring) - getAnimeByStudio — anime produced by a specific studio - getCharacterInfo — character detail with anime list - getStaffInfo — staff detail with anime list - searchCharacters — search characters by name - searchStaff — search staff by name #### New Streaming & Download Features - extractSubtitles — extract subtitle URLs from sources - getBestStream — automatic quality fallback (1080p → 720p → 360p) - getDownloadUrl — dedicated download URL endpoint - getBatchSources — fetch multiple episode sources in parallel #### New API Endpoints (17 new) - GET /api/trending/daily — daily trending anime - GET /api/trending/weekly — weekly trending anime - GET /api/top — top anime by score - GET /api/random — random anime of the day - GET /api/multi-search — combined query + filters - GET /api/season/:year/:season — seasonal anime - GET /api/studio/:name — anime by studio - GET /api/genres — all genres list - GET /api/tags — all tags list - GET /api/genre/:name — anime by genre - GET /api/year/:year — anime by year - GET /api/status/:status — anime by status - GET /api/format/:format — anime by format - GET /api/character/:id — character detail - GET /api/staff/:id — staff detail - GET /api/characters — search characters - GET /api/staff — search staff - GET /api/episodes/:id/batch — batch episode sources - GET /api/stream — streaming with quality fallback - GET /api/download — download URL - GET /api/compare/:id1/:id2 — compare two anime - GET /api/stats/genre — genre statistics - GET /api/calendar — monthly airing calendar - GET /api/timeline/:id — anime release timeline #### Streaming Improvements - Subtitle URL extraction from pipe responses - Quality fallback: tries 1080p → 720p → 480p → 360p automatically - Batch episode fetching (up to 5 parallel requests) - Dedicated download endpoint with provider metadata - Cache headers: episodes/sources (2min), info (5min), genres/tags (24h) #### Version synced to 2.0.0 across all files ## v1.4.0 - Added creator attribution middleware — injects author info into every response - Fixed Vercel deployment: replaced legacy `builds`/`routes` config with modern `functions` config - Added `api/index.js` serverless entry point - Security headers: removed deprecated `X-XSS-Protection`, added `Strict-Transport-Security` (HSTS) - Rate limiter: uses `x-forwarded-for` header for correct IP detection on Vercel - Rate limiter: added periodic IP entry pruning when >200 IPs tracked - Cache: added periodic expired entry cleanup when cache reaches 80% capacity - Version synced to 1.4.0 ## v1.3.0 - Full landing page upgrade to match AniKotoAPI style - Added canvas particle effects with cyan-colored floating particles - Added scroll-reveal animations (IntersectionObserver) - Added animated stat counters that count up on scroll - Added infinite scrolling marquee with 8 feature badges - Added live interactive API console with 5 preset endpoint buttons - Added sidebar endpoint explorer with 16 endpoints and multi-language code tabs - Added 4 interactive playground cards (Search, Info, Episodes, Trending) - Added custom scrollbar styling - Added JetBrains Mono font for code blocks - Added 4-column grid footer - Added fixed header with scroll-aware blur/glass effect - Added ambient orb gradient animations - Added CTA section with gradient overlay - Color scheme updated to match MiruroAPI brand (cyan #38bdf8 + indigo #818cf8) - All branding updated: AniKotoAPI references → MiruroAPI - OG/Twitter meta tags updated for mirurotvapi.vercel.app - JSON-LD structured data updated - Real Miruro SVG favicons used in header and footer ## v1.2.0 - Fixed critical response format bug: all endpoints now return {success: true, results: data} - Root cause: createApiRoutes() had (app, jsonResponse, jsonError) but was called with (jsonResponse, jsonError), shifting all params - Every jsonResponse() call was actually calling jsonError(), returning {success: false, message: data} - Health endpoint worked because it used res.json() directly, bypassing the wrapper - All 18 endpoints verified working ## v1.1.0 - Added Swagger UI interactive docs at /docs - Added OpenAPI 3.0 spec at /openapi.json - Added mappings field in episodes response - Added Docker support (Dockerfile + .dockerignore) - Improved landing page with premium design - Added "Try it" buttons on all endpoints - Health endpoint now includes version, providers list, and endpoint count - Version bump to 1.1.0 ## v1.0.0 - Initial release - AniList GraphQL integration for anime metadata - Miruro pipe integration for streaming sources - 16 API endpoints: search, suggestions, trending, popular, upcoming, recent, spotlight, schedule, filter, info, characters, relations, recommendations, episodes, sources, watch - In-memory caching with TTL - CORS support - Health endpoint - Deployed on Vercel