mirror of
https://github.com/Shineii86/MiruroAPI.git
synced 2026-10-22 18:25:11 +00:00
v1.3.0: Full landing page upgrade + feature parity with AniKotoAPI
- Full index.html rewrite with AniKotoAPI-style features: * Canvas particle effects (cyan particles) * Scroll-reveal animations (IntersectionObserver) * Animated stat counters (count up on scroll) * Infinite scrolling marquee (8 feature badges) * Live interactive API console (5 presets: Search, Trending, Episodes, Info, Health) * Sidebar endpoint explorer (16 endpoints, multi-language tabs: cURL/JS/Python) * 4 interactive playground cards (Search, Info, Episodes, Trending) * Custom scrollbar, JetBrains Mono font * 4-column grid footer with API/Resources/Legal * Fixed header with scroll-aware glass blur * Ambient orb gradient animations * CTA section with gradient overlay - Added public/404.html (glitch animation error page) - Added public/manifest.json (PWA, theme: #38bdf8) - Added public/robots.txt (Allow /, Disallow /api) - Added public/sitemap.xml (4 URLs) - Added public/tos.html (13 sections) - Added public/privacy.html (8 sections) - Added .env.example, CONTRIBUTING.md, LICENSE, render.yaml, test.js - Added docs/ (5 files: index, endpoints, streaming, examples, architecture) - Updated server.js: clean URL routes (/tos, /privacy), 404.html fallback - Updated package.json: devDependencies nodemon, repository, dev script - All branding: AniKotoAPI → MiruroAPI, cyan color scheme (#38bdf8)
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
# Streaming Flow Guide
|
||||
|
||||
This guide explains how to get streaming URLs from MiruroAPI in 3 steps.
|
||||
|
||||
## Overview
|
||||
|
||||
```
|
||||
Step 1: Get Episodes → /api/episodes/:anilistId
|
||||
Step 2: Get Stream URLs → /api/watch/:provider/:anilistId/:category/:slug
|
||||
Step 3: Play M3U8 → Use HLS player
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Get Episodes
|
||||
|
||||
Each anime has episodes from multiple providers. Fetch the episode list with the AniList ID.
|
||||
|
||||
**Request:**
|
||||
|
||||
```bash
|
||||
curl "https://mirurotvapi.vercel.app/api/episodes/20"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"results": {
|
||||
"providers": {
|
||||
"kiwi": {
|
||||
"meta": { "id": "1571", "title": "Naruto", "type": "TV" },
|
||||
"episodes": {
|
||||
"sub": [
|
||||
{
|
||||
"id": "watch/kiwi/20/sub/animepahe-1",
|
||||
"number": 1,
|
||||
"title": "Enter: Naruto Uzumaki!",
|
||||
"image": "https://image.tmdb.org/t/p/original/...",
|
||||
"airDate": "2002-10-03",
|
||||
"audio": "sub",
|
||||
"filler": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Key field:** `id` in each episode — Pass this to the next step.
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Get Stream URLs
|
||||
|
||||
Use the episode `id` from Step 1 to get M3U8 streaming URLs.
|
||||
|
||||
**Request:**
|
||||
|
||||
```bash
|
||||
curl "https://mirurotvapi.vercel.app/api/watch/kiwi/20/sub/animepahe-1"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"results": {
|
||||
"streams": [
|
||||
{
|
||||
"url": "https://vault-01.uwucdn.top/stream/.../uwu.m3u8",
|
||||
"type": "hls",
|
||||
"quality": "360p",
|
||||
"resolution": { "width": 640, "height": 360 },
|
||||
"codec": "h264",
|
||||
"audio": "sub",
|
||||
"fansub": "df68",
|
||||
"isActive": false,
|
||||
"referer": "https://kwik.cx/e/..."
|
||||
}
|
||||
],
|
||||
"download": "https://pahe.win/LJmbA"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Done!** Use `streams[0].url` in your HLS video player.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Play M3U8
|
||||
|
||||
### HLS.js (Browser)
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<video id="player" controls></video>
|
||||
|
||||
<script>
|
||||
const url = 'https://vault-01.uwucdn.top/stream/.../uwu.m3u8';
|
||||
const video = document.getElementById('player');
|
||||
|
||||
if (Hls.isSupported()) {
|
||||
const hls = new Hls();
|
||||
hls.loadSource(url);
|
||||
hls.attachMedia(video);
|
||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url; // Native HLS (Safari)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JavaScript Example
|
||||
|
||||
```javascript
|
||||
async function getStreamUrl(anilistId) {
|
||||
// Step 1: Get episodes
|
||||
const episodesRes = await fetch(`https://mirurotvapi.vercel.app/api/episodes/${anilistId}`);
|
||||
const episodesData = await episodesRes.json();
|
||||
const providers = episodesData.results.providers;
|
||||
|
||||
// Pick first provider with sub episodes
|
||||
const provider = Object.keys(providers)[0];
|
||||
const episodes = providers[provider].episodes.sub;
|
||||
|
||||
if (!episodes || episodes.length === 0) {
|
||||
throw new Error('No episodes found');
|
||||
}
|
||||
|
||||
// Use first episode's id
|
||||
const episodeId = episodes[0].id; // "watch/kiwi/20/sub/animepahe-1"
|
||||
const parts = episodeId.split('/');
|
||||
const category = parts[3]; // "sub"
|
||||
const slug = parts[4]; // "animepahe-1"
|
||||
|
||||
// Step 2: Get stream URLs
|
||||
const streamRes = await fetch(`https://mirurotvapi.vercel.app/api/watch/${provider}/${anilistId}/${category}/${slug}`);
|
||||
const streamData = await streamRes.json();
|
||||
|
||||
return streamData.results.streams[0].url; // "https://...m3u8"
|
||||
}
|
||||
|
||||
// Usage
|
||||
getStreamUrl(20)
|
||||
.then(url => console.log('Stream URL:', url))
|
||||
.catch(err => console.error('Error:', err));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Python Example
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def get_stream_url(anilist_id):
|
||||
base = "https://mirurotvapi.vercel.app/api"
|
||||
|
||||
# Step 1: Get episodes
|
||||
episodes_res = requests.get(f"{base}/episodes/{anilist_id}")
|
||||
episodes_data = episodes_res.json()
|
||||
providers = episodes_data['results']['providers']
|
||||
|
||||
# Pick first provider
|
||||
provider = list(providers.keys())[0]
|
||||
episodes = providers[provider]['episodes']['sub']
|
||||
|
||||
if not episodes:
|
||||
raise Exception("No episodes found")
|
||||
|
||||
episode_id = episodes[0]['id'] # "watch/kiwi/20/sub/animepahe-1"
|
||||
parts = episode_id.split('/')
|
||||
category = parts[3]
|
||||
slug = parts[4]
|
||||
|
||||
# Step 2: Get stream URLs
|
||||
stream_res = requests.get(f"{base}/watch/{provider}/{anilist_id}/{category}/{slug}")
|
||||
stream_data = stream_res.json()
|
||||
|
||||
return stream_data['results']['streams'][0]['url']
|
||||
|
||||
# Usage
|
||||
url = get_stream_url(20)
|
||||
print(f"Stream URL: {url}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sub & Dub
|
||||
|
||||
Providers return both `sub` and `dub` episode lists:
|
||||
|
||||
```javascript
|
||||
const eps = await fetch("/api/episodes/20").then(r => r.json());
|
||||
const kiwi = eps.results.providers.kiwi.episodes;
|
||||
|
||||
// Get sub episodes
|
||||
const subEps = kiwi.sub; // [{ id: "watch/kiwi/20/sub/animepahe-1", ... }]
|
||||
|
||||
// Get dub episodes (if available)
|
||||
const dubEps = kiwi.dub; // [{ id: "watch/kiwi/20/dub/...", ... }]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Providers
|
||||
|
||||
| Provider | Sub | Dub | Download | Skip Times |
|
||||
|:---|:---:|:---:|:---:|:---:|
|
||||
| kiwi | ✅ | ❌ | ✅ | ❌ |
|
||||
| pewe | ✅ | ❌ | ❌ | ❌ |
|
||||
| bee | ✅ | ✅ | ❌ | ❌ |
|
||||
| bonk | ✅ | ✅ | ✅ | ✅ |
|
||||
| bun | ✅ | ✅ | ❌ | ❌ |
|
||||
| ally | ✅ | ❌ | ✅ | ❌ |
|
||||
| nun | ✅ | ❌ | ❌ | ❌ |
|
||||
| twin | ✅ | ✅ | ❌ | ❌ |
|
||||
| cog | ✅ | ❌ | ❌ | ❌ |
|
||||
| moo | ✅ | ❌ | ✅ | ❌ |
|
||||
| hop | ❌ | ✅ | ❌ | ❌ |
|
||||
| telli | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "No episodes found" | Check the AniList ID is correct (use `/api/search` first) |
|
||||
| "No providers" | The anime may not be available on any provider |
|
||||
| Stream URL 403 | Some servers require specific referrer headers |
|
||||
| CORS error | Use a proxy or access from server-side |
|
||||
Reference in New Issue
Block a user