Files
MiruroAPI/CHANGELOG.md
Shinei Nouzen 2c97ca2dd8 docs: add Cloudflare Worker edition documentation
- README.md: Added Worker deployment section, updated troubleshooting
  - Fix 1: Cloudflare Worker (best — free, works)
  - Fix 2: ScraperAPI (paid, 9/mo)
  - Fix 3: FlareSolverr (self-hosted)
  - Fix 4: Self-host API
  - Added Worker vs Vercel comparison table
- docs/architecture.md: Added Worker architecture section
  - Why Workers work (edge-to-edge bypass)
  - Worker runtime differences table
  - 15 Worker endpoints listed
  - Deploy instructions
- CHANGELOG.md: Added v2.3.1 entry for Worker edition
2026-07-02 09:34:18 +05:30

18 KiB

Changelog

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

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