diff --git a/public/index.html b/public/index.html index 60c0b18..fe6dffb 100644 --- a/public/index.html +++ b/public/index.html @@ -10,7 +10,7 @@ - + @@ -26,13 +26,13 @@ - + - + @@ -278,7 +278,7 @@ "@context": "https://schema.org", "@type": "WebAPI", "name": "MiruroAPI", - "description": "Free RESTful API for anime streaming data. 35 endpoints, 12 providers, M3U8 streaming URLs.", + "description": "Free RESTful API for anime streaming data. 44 endpoints, 12 providers, M3U8 streaming URLs.", "url": "https://mirurotvapi.vercel.app", "image": "https://mirurotvapi.vercel.app/og-image.png", "documentation": "https://mirurotvapi.vercel.app/docs", @@ -326,7 +326,7 @@
Free · No API key · Open source

The Anime Streaming API
for Your Next Project

-

Search, discover, and stream anime with M3U8 URLs. Powered by AniList GraphQL + Miruro providers. 35 endpoints, 12 providers, zero config.

+

Search, discover, and stream anime with M3U8 URLs. Powered by AniList GraphQL + Miruro providers. 44 endpoints, 12 providers, zero config.

@@ -370,7 +370,7 @@ fetch("https://mirurotvapi.vercel.app/api/search?query=naruto")
-
0
API Endpoints
+
0
API Endpoints
0
Streaming Providers
0
Anime Indexed
M3U8
Stream Format
@@ -719,22 +719,68 @@ fetch("https://mirurotvapi.vercel.app/api/search?query=naruto") /* ── Explorer ── */ const explorerData = [ + // ---- FEATURE: Search & Discovery ---- { id: 'search', title: 'Search', desc: 'Full-text anime search with 20+ fields per result. Paginated.', path: '/search?query={q}&page={n}&per_page={n}', params: [{ name: 'query', type: 'string', desc: 'Search query' }, { name: 'page', type: 'number', desc: 'Page (default 1)' }, { name: 'per_page', type: 'number', desc: 'Results per page (default 20)' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/search?query=naruto"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/search?query=naruto");\nconst data = await res.json();\nconsole.log(data.results);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/search", params={"query": "naruto"})\nprint(r.json())' } }, { id: 'suggestions', title: 'Suggestions', desc: 'Lightweight autocomplete for dropdowns. Max 8 results.', path: '/suggestions?query={q}', params: [{ name: 'query', type: 'string', desc: 'Partial query' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/suggestions?query=naru"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/suggestions?query=naru");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/suggestions", params={"query": "naru"})\nprint(r.json())' } }, - { id: 'info', title: 'Anime Info', desc: 'Everything AniList has — characters, staff, relations, recommendations, trailer, stats.', path: '/info/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/info/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/info/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/info/20")\nprint(r.json())' } }, - { id: 'characters', title: 'Characters', desc: 'Paginated characters with Japanese voice actors.', path: '/characters/{anilistId}?page={n}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }, { name: 'page', type: 'number', desc: 'Page (default 1)' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/characters/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/characters/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/characters/20")\nprint(r.json())' } }, - { id: 'relations', title: 'Relations', desc: 'Sequels, prequels, side stories, spin-offs.', path: '/relations/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/relations/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/relations/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/relations/20")\nprint(r.json())' } }, - { id: 'recommendations', title: 'Recommendations', desc: 'Community recommendations sorted by rating.', path: '/recommendations/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/recommendations/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/recommendations/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/recommendations/20")\nprint(r.json())' } }, - { id: 'episodes', title: 'Episodes', desc: 'Fetch all episodes from multiple providers (sub, dub, download).', path: '/episodes/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/episodes/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/episodes/20");\nconst data = await res.json();\nconsole.log(data.providers);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/episodes/20")\nprint(r.json())' } }, - { id: 'watch', title: 'Watch / Stream', desc: 'Get M3U8 streaming URL from episode ID. 12 providers.', path: '/watch/{provider}/{id}/{category}/{slug}', params: [{ name: 'provider', type: 'string', desc: 'Provider name (kiwi, pewe, etc.)' }, { name: 'id', type: 'string', desc: 'Episode ID' }, { name: 'category', type: 'string', desc: 'Category (sub, dub, raw)' }, { name: 'slug', type: 'string', desc: 'Episode slug' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/watch/kiwi/episode-id/sub/episode-slug"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/watch/kiwi/episode-id/sub/episode-slug");\nconst data = await res.json();\nconsole.log(data.streams[0].url);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/watch/kiwi/episode-id/sub/episode-slug")\nprint(r.json())' } }, + { id: 'filter', title: 'Filter', desc: 'Filter by genre, tag, year, season, format, status, sort.', path: '/filter?genre={g}&format={f}&year={y}', params: [{ name: 'genre', type: 'string', desc: 'Genre name' }, { name: 'format', type: 'string', desc: 'TV, MOVIE, OVA, etc.' }, { name: 'year', type: 'number', desc: 'Release year' }, { name: 'season', type: 'string', desc: 'WINTER, SPRING, SUMMER, FALL' }, { name: 'status', type: 'string', desc: 'RELEASING, FINISHED, NOT_YET_RELEASED' }, { name: 'sort', type: 'string', desc: 'POPULARITY_DESC, SCORE_DESC, etc.' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/filter?genre=Action&format=TV"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/filter?genre=Action&format=TV");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/filter", params={"genre": "Action", "format": "TV"})\nprint(r.json())' } }, + { id: 'multi-search', title: 'Multi-Search', desc: 'Combined search with genre, status, year, format filters.', path: '/multi-search?q={q}&genre={g}', params: [{ name: 'q', type: 'string', desc: 'Search query' }, { name: 'genre', type: 'string', desc: 'Genre filter' }, { name: 'status', type: 'string', desc: 'Status filter' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/multi-search?q=naruto&genre=Action"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/multi-search?q=naruto&genre=Action");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/multi-search", params={"q": "naruto", "genre": "Action"})\nprint(r.json())' } }, + + // ---- FEATURE: Collections ---- { id: 'trending', title: 'Trending', desc: 'Currently trending anime across the community.', path: '/trending', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/trending"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/trending");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/trending")\nprint(r.json())' } }, + { id: 'trending-daily', title: 'Trending Daily', desc: 'Daily trending anime rotation.', path: '/trending/daily', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/trending/daily"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/trending/daily");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/trending/daily")\nprint(r.json())' } }, + { id: 'trending-weekly', title: 'Trending Weekly', desc: 'Weekly trending anime rotation.', path: '/trending/weekly', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/trending/weekly"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/trending/weekly");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/trending/weekly")\nprint(r.json())' } }, { id: 'popular', title: 'Popular', desc: 'Most popular anime of all time by user count.', path: '/popular', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/popular"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/popular");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/popular")\nprint(r.json())' } }, + { id: 'top', title: 'Top', desc: 'Top rated anime by AniList score.', path: '/top', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/top"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/top");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/top")\nprint(r.json())' } }, { id: 'upcoming', title: 'Upcoming', desc: 'Most anticipated anime that haven\'t aired yet.', path: '/upcoming', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/upcoming"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/upcoming");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/upcoming")\nprint(r.json())' } }, { id: 'recent', title: 'Recent Episodes', desc: 'Currently airing / this season\'s anime.', path: '/recent', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/recent"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/recent");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/recent")\nprint(r.json())' } }, { id: 'spotlight', title: 'Spotlight', desc: 'Top 10 trending + popular. Perfect for hero banners.', path: '/spotlight', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/spotlight"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/spotlight");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/spotlight")\nprint(r.json())' } }, { id: 'schedule', title: 'Schedule', desc: 'Upcoming episodes with UNIX timestamps.', path: '/schedule', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/schedule"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/schedule");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/schedule")\nprint(r.json())' } }, - { id: 'filter', title: 'Filter', desc: 'Filter by genre, tag, year, season, format, status, sort.', path: '/filter?genre={g}&format={f}&year={y}', params: [{ name: 'genre', type: 'number', desc: 'AniList genre ID' }, { name: 'format', type: 'string', desc: 'TV, MOVIE, OVA, etc.' }, { name: 'year', type: 'number', desc: 'Release year' }, { name: 'season', type: 'string', desc: 'WINTER, SPRING, SUMMER, FALL' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/filter?genre=1&format=TV"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/filter?genre=1&format=TV");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/filter", params={"genre": "1", "format": "TV"})\nprint(r.json())' } }, + { id: 'random', title: 'Random', desc: 'Random anime for discovery. Changes each request.', path: '/random', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/random"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/random");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/random")\nprint(r.json())' } }, + { id: 'upcoming-countdown', title: 'Upcoming Countdown', desc: 'Next 10 episodes airing soon with countdown.', path: '/upcoming/countdown', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/upcoming/countdown"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/upcoming/countdown");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/upcoming/countdown")\nprint(r.json())' } }, + + // ---- FEATURE: Seasonal & Studio ---- + { id: 'season', title: 'Seasonal', desc: 'Anime by year and season.', path: '/season/{year}/{season}', params: [{ name: 'year', type: 'number', desc: 'Release year' }, { name: 'season', type: 'string', desc: 'WINTER, SPRING, SUMMER, FALL' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/season/2025/spring"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/season/2025/spring");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/season/2025/spring")\nprint(r.json())' } }, + { id: 'studio', title: 'Studio', desc: 'Anime by studio name (MAPPA, Ufotable, etc.).', path: '/studio/{name}', params: [{ name: 'name', type: 'string', desc: 'Studio name' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/studio/MAPPA"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/studio/MAPPA");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/studio/MAPPA")\nprint(r.json())' } }, + + // ---- FEATURE: Genres & Tags ---- { id: 'genres', title: 'Genres', desc: 'List all available genres with AniList IDs.', path: '/genres', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/genres"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/genres");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/genres")\nprint(r.json())' } }, + { id: 'tags', title: 'Tags', desc: 'List all available tags (violet, mind game, etc.).', path: '/tags', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/tags"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/tags");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/tags")\nprint(r.json())' } }, + { id: 'genre', title: 'Genre', desc: 'Anime by specific genre name.', path: '/genre/{name}', params: [{ name: 'name', type: 'string', desc: 'Genre name (Action, Romance, etc.)' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/genre/Action"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/genre/Action");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/genre/Action")\nprint(r.json())' } }, + { id: 'year', title: 'Year', desc: 'Anime by release year.', path: '/year/{year}', params: [{ name: 'year', type: 'number', desc: 'Release year' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/year/2024"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/year/2024");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/year/2024")\nprint(r.json())' } }, + { id: 'status', title: 'Status', desc: 'Anime by airing status.', path: '/status/{status}', params: [{ name: 'status', type: 'string', desc: 'RELEASING, FINISHED, NOT_YET_RELEASED' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/status/RELEASING"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/status/RELEASING");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/status/RELEASING")\nprint(r.json())' } }, + { id: 'format', title: 'Format', desc: 'Anime by format type.', path: '/format/{format}', params: [{ name: 'format', type: 'string', desc: 'TV, MOVIE, OVA, ONA, SPECIAL' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/format/MOVIE"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/format/MOVIE");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/format/MOVIE")\nprint(r.json())' } }, + + // ---- FEATURE: Character & Staff ---- + { id: 'character', title: 'Character', desc: 'Character detail with animeography and voice actors.', path: '/character/{id}', params: [{ name: 'id', type: 'number', desc: 'AniList character ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/character/1"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/character/1");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/character/1")\nprint(r.json())' } }, + { id: 'staff', title: 'Staff', desc: 'Staff detail with works and roles.', path: '/staff/{id}', params: [{ name: 'id', type: 'number', desc: 'AniList staff ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/staff/1"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/staff/1");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/staff/1")\nprint(r.json())' } }, + { id: 'characters-search', title: 'Characters Search', desc: 'Search characters by name.', path: '/characters?query={q}', params: [{ name: 'query', type: 'string', desc: 'Character name' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/characters?query=kaneki"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/characters?query=kaneki");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/characters", params={"query": "kaneki"})\nprint(r.json())' } }, + { id: 'staff-search', title: 'Staff Search', desc: 'Search staff by name.', path: '/staff?query={q}', params: [{ name: 'query', type: 'string', desc: 'Staff name' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/staff?query=oda"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/staff?query=oda");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/staff", params={"query": "oda"})\nprint(r.json())' } }, + + // ---- FEATURE: Anime Details ---- + { id: 'info', title: 'Anime Info', desc: 'Everything AniList has — characters, staff, relations, recommendations, trailer, stats.', path: '/info/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/info/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/info/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/info/20")\nprint(r.json())' } }, + { id: 'anime-characters', title: 'Anime Characters', desc: 'Characters for an anime with voice actors.', path: '/anime/{id}/characters', params: [{ name: 'id', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/anime/20/characters"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/anime/20/characters");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/anime/20/characters")\nprint(r.json())' } }, + { id: 'relations', title: 'Relations', desc: 'Sequels, prequels, side stories, spin-offs.', path: '/anime/{id}/relations', params: [{ name: 'id', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/anime/20/relations"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/anime/20/relations");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/anime/20/relations")\nprint(r.json())' } }, + { id: 'recommendations', title: 'Recommendations', desc: 'Community recommendations sorted by rating.', path: '/anime/{id}/recommendations', params: [{ name: 'id', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/anime/20/recommendations"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/anime/20/recommendations");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/anime/20/recommendations")\nprint(r.json())' } }, + + // ---- FEATURE: Streaming ---- + { id: 'episodes', title: 'Episodes', desc: 'Fetch all episodes from multiple providers (sub, dub, download).', path: '/episodes/{anilistId}', params: [{ name: 'anilistId', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/episodes/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/episodes/20");\nconst data = await res.json();\nconsole.log(data.providers);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/episodes/20")\nprint(r.json())' } }, + { id: 'batch-episodes', title: 'Batch Episodes', desc: 'Fetch sources for multiple episodes in one request.', path: '/episodes/{id}/batch?provider={p}&category={c}&slugs={s}', params: [{ name: 'id', type: 'number', desc: 'AniList ID' }, { name: 'provider', type: 'string', desc: 'Provider name' }, { name: 'category', type: 'string', desc: 'sub, dub, raw' }, { name: 'slugs', type: 'string', desc: 'Comma-separated slugs' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/episodes/20/batch?provider=kiwi&category=sub&slugs=animepahe-1,animepahe-2"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/episodes/20/batch?provider=kiwi&category=sub&slugs=animepahe-1,animepahe-2");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/episodes/20/batch", params={"provider": "kiwi", "category": "sub", "slugs": "animepahe-1,animepahe-2"})\nprint(r.json())' } }, + { id: 'sources', title: 'Sources', desc: 'Detailed streaming sources for an episode.', path: '/sources?episodeId={e}&provider={p}&anilistId={a}&category={c}', params: [{ name: 'episodeId', type: 'string', desc: 'Episode ID' }, { name: 'provider', type: 'string', desc: 'Provider name' }, { name: 'anilistId', type: 'number', desc: 'AniList ID' }, { name: 'category', type: 'string', desc: 'sub, dub, raw' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/sources?episodeId=ep1&provider=kiwi&anilistId=20&category=sub"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/sources?episodeId=ep1&provider=kiwi&anilistId=20&category=sub");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/sources", params={"episodeId": "ep1", "provider": "kiwi", "anilistId": "20", "category": "sub"})\nprint(r.json())' } }, + { id: 'stream', title: 'Stream', desc: 'Stream URL with quality fallback. Returns best available quality.', path: '/stream?provider={p}&anilistId={a}&category={c}&slug={s}&quality={q}', params: [{ name: 'provider', type: 'string', desc: 'Provider name' }, { name: 'anilistId', type: 'number', desc: 'AniList ID' }, { name: 'category', type: 'string', desc: 'sub, dub, raw' }, { name: 'slug', type: 'string', desc: 'Episode slug' }, { name: 'quality', type: 'string', desc: '1080p, 720p, etc.' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/stream?provider=kiwi&anilistId=20&category=sub&slug=animepahe-1&quality=1080p"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/stream?provider=kiwi&anilistId=20&category=sub&slug=animepahe-1&quality=1080p");\nconst data = await res.json();\nconsole.log(data.results.bestStream.url);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/stream", params={"provider": "kiwi", "anilistId": "20", "category": "sub", "slug": "animepahe-1"})\nprint(r.json())' } }, + { id: 'download', title: 'Download', desc: 'Download URL for an episode.', path: '/download?provider={p}&anilistId={a}&category={c}&slug={s}', params: [{ name: 'provider', type: 'string', desc: 'Provider name' }, { name: 'anilistId', type: 'number', desc: 'AniList ID' }, { name: 'category', type: 'string', desc: 'sub, dub, raw' }, { name: 'slug', type: 'string', desc: 'Episode slug' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/download?provider=kiwi&anilistId=20&category=sub&slug=animepahe-1"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/download?provider=kiwi&anilistId=20&category=sub&slug=animepahe-1");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/download", params={"provider": "kiwi", "anilistId": "20", "category": "sub", "slug": "animepahe-1"})\nprint(r.json())' } }, + { id: 'watch', title: 'Watch / Stream', desc: 'Get M3U8 streaming URL from episode ID. 12 providers. Returns streams, subtitles, and best stream.', path: '/watch/{provider}/{id}/{category}/{slug}', params: [{ name: 'provider', type: 'string', desc: 'Provider name (kiwi, pewe, etc.)' }, { name: 'id', type: 'string', desc: 'AniList ID' }, { name: 'category', type: 'string', desc: 'Category (sub, dub, raw)' }, { name: 'slug', type: 'string', desc: 'Episode slug' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1");\nconst data = await res.json();\nconsole.log(data.results.bestStream.url);', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1")\nprint(r.json())' } }, + + // ---- FEATURE: Utility ---- + { id: 'compare', title: 'Compare', desc: 'Compare two anime side by side.', path: '/compare/{id1}/{id2}', params: [{ name: 'id1', type: 'number', desc: 'First AniList ID' }, { name: 'id2', type: 'number', desc: 'Second AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/compare/20/21"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/compare/20/21");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/compare/20/21")\nprint(r.json())' } }, + { id: 'stats-genre', title: 'Genre Stats', desc: 'Genre distribution statistics across the database.', path: '/stats/genre', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/stats/genre"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/stats/genre");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/stats/genre")\nprint(r.json())' } }, + { id: 'calendar', title: 'Calendar', desc: 'Monthly airing calendar with episode counts.', path: '/calendar?year={y}&month={m}', params: [{ name: 'year', type: 'number', desc: 'Year (default current)' }, { name: 'month', type: 'number', desc: 'Month 1-12 (default current)' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/calendar?year=2025&month=6"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/calendar?year=2025&month=6");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/calendar", params={"year": "2025", "month": "6"})\nprint(r.json())' } }, + { id: 'timeline', title: 'Timeline', desc: 'Anime timeline with episodes and airing dates.', path: '/timeline/{id}', params: [{ name: 'id', type: 'number', desc: 'AniList ID' }], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/timeline/20"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/timeline/20");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/timeline/20")\nprint(r.json())' } }, + + // ---- FEATURE: System ---- + { id: 'health', title: 'Health', desc: 'Health check — returns version, uptime, and environment.', path: '/health', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/health"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/health");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/health")\nprint(r.json())' } }, + { id: 'stats', title: 'Stats', desc: 'API statistics — total requests, cache size, uptime.', path: '/stats', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/stats"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/stats");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/stats")\nprint(r.json())' } }, + { id: 'providers', title: 'Providers', desc: 'List all available streaming providers.', path: '/providers', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/providers"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/providers");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/providers")\nprint(r.json())' } }, + { id: 'openapi', title: 'OpenAPI Spec', desc: 'Raw OpenAPI 3.0.3 specification.', path: '/openapi', params: [], code: { curl: 'curl "https://mirurotvapi.vercel.app/api/openapi"', js: 'const res = await fetch("https://mirurotvapi.vercel.app/api/openapi");\nconst data = await res.json();', python: 'import requests\nr = requests.get("https://mirurotvapi.vercel.app/api/openapi")\nprint(r.json())' } }, ]; const navEl = document.getElementById('explorerNav'); const panelEl = document.getElementById('explorerPanel');