DISCLAIMER: This API is experimental and not reliable. Use at your own risk. No guarantees on uptime or data accuracy. I'M NOT RESPONSIBLE FOR ANY UNETHICAL USAGES OR LEGAL TROUBLES, ONLY FOR EDUCATION PURPOSE.
Current Status: 10/09/2026 (working, native providers)
A anime streaming API built for scale. Kuhi provides a clean REST interface to search, filter, and stream anime content with automatic source extraction and proxy capabilities. Streaming runs on 10 native Python providers (no sidecars, no external aggregator needed) — every /extract call races all providers concurrently and the fastest success wins, with a rolling latency table that keeps the closest/fastest provider as the default.
- Smart Search - Search by anime name or AniList ID
- Auto-Extraction - Races 10 native providers, fastest stream wins
- Sub/Dub flags -
?type=sub|dubon extraction, per-audio episode lists - Latency-ranked default - Fastest provider becomes the default automatically
- Movie Detection - Automatically handles movies vs episodes
- Decryption Pipeline - Native MegaPlay/FlixCloud extractors in Python
- CORS Proxy - Built-in proxy for bypassing CDN restrictions
- HLS Streaming - Full M3U8 playlist and segment proxying
- Python 3.8+
- pip
- Clone the repository:
git clone https://github.com/aryaniiil/kuhi-anime-api
cd Kuhi-anime-api- Install dependencies:
python -m pip install -r requirements.txt- Run the server:
uvicorn api:app --reload- Access the API:
http://127.0.0.1:8000
Kuhi/
├── src/
│ ├── __init__.py # Package initializer
│ ├── main.py # FastAPI app & proxy endpoints
│ ├── endpoints.py # Anime API routes
│ ├── extractor.py # AniList data fetchers (+ Miruro fallback)
│ ├── providers/ # Native streaming providers (no sidecars)
│ │ ├── _race.py # Fastest-wins race + latency-ranked default
│ │ ├── _match.py # Title matching / series selection
│ │ ├── _media.py # AniList + ARM + AniZip identity
│ │ ├── _http.py # Shared HTTP helpers
│ │ ├── _cache.py # TTL cache
│ │ └── anineko.py, anizone.py, anikoto.py, reanime.py, ...
│ ├── parser.py # Data transformation utilities
│ ├── queries.py # GraphQL query templates
│ └── config.py # Configuration & constants
├── api.py # Alternative entry point
├── .gitignore # Git ignore rules
└── README.md # This file
Search anime by keyword with pagination.
Parameters:
query(string, required) - Search termpage(int, default: 1) - Page numberper_page(int, default: 20, max: 50) - Results per page
Example:
curl "http://127.0.0.1:8000/anime/search?query=naruto&page=1"Lightweight autocomplete search for dropdowns.
Parameters:
query(string, required) - Search term
Example:
curl "http://127.0.0.1:8000/anime/suggestions?query=one%20piece"List all available genres for filtering.
Example:
curl "http://127.0.0.1:8000/anime/genres"Top 10 trending and popular anime.
Example:
curl "http://127.0.0.1:8000/anime/spotlight"Currently trending anime with pagination.
Parameters:
page(int, default: 1)per_page(int, default: 20, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/trending?page=1&per_page=20"Most popular anime of all time.
Parameters:
page(int, default: 1)per_page(int, default: 20, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/popular"Upcoming anime releases.
Parameters:
page(int, default: 1)per_page(int, default: 20, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/upcoming"Recently aired episodes.
Parameters:
page(int, default: 1)per_page(int, default: 20, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/recent"Airing schedule for upcoming episodes.
Parameters:
page(int, default: 1)per_page(int, default: 20, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/schedule"Filter anime by multiple criteria.
Parameters:
genre(string, optional) - Genre name (get from /anime/genres)tag(string, optional) - Tag nameyear(int, optional) - Season yearseason(string, optional) - Season (WINTER, SPRING, SUMMER, FALL)format(string, optional) - Format (TV, MOVIE, OVA, ONA, SPECIAL)status(string, optional) - Status (RELEASING, FINISHED, NOT_YET_RELEASED)sort(string, default: POPULARITY_DESC) - Sort orderpage(int, default: 1)per_page(int, default: 20, max: 50)
Sort Options:
SCORE_DESC- Highest ratedPOPULARITY_DESC- Most popularTRENDING_DESC- Currently trendingSTART_DATE_DESC- Recently startedFAVOURITES_DESC- Most favoritedUPDATED_AT_DESC- Recently updated
Example:
curl "http://127.0.0.1:8000/anime/filter?genre=Action&sort=SCORE_DESC&year=2024"Complete anime information including characters, relations, staff, and recommendations.
Example:
curl "http://127.0.0.1:8000/anime/info/21"Character list with voice actors.
Parameters:
page(int, default: 1)per_page(int, default: 25, max: 50)
Example:
curl "http://127.0.0.1:8000/anime/anime/21/characters"Related anime (sequels, prequels, spin-offs).
Example:
curl "http://127.0.0.1:8000/anime/anime/21/relations"Recommended similar anime.
Parameters:
page(int, default: 1)per_page(int, default: 10, max: 25)
Example:
curl "http://127.0.0.1:8000/anime/anime/21/recommendations"Episode lists merged from all native providers concurrently, split by audio (sub / dub). Falls back to the legacy pipe if no native provider matches.
Example:
curl "http://127.0.0.1:8000/anime/episodes/21"
# → { anilistId, source: "native", providers: { anineko: { episodes: { sub: [...], dub: [...] }, meta }, ... } }Magic endpoint - Races all native providers concurrently; fastest success wins and feeds the latency table that picks the default provider.
Parameters:
query(string, required) - AniList ID (21) or anime name (violet evergarden)e(int, default: 1) - Episode numbertype(string, default:sub) - Audio:subordubprovider(string, optional) - Force one provider (anineko,anizone,anikoto,reanime,aniwaves,kaa,anibd,animegg,mkissa,animeonsen). Omit for fastest-wins race.
Features:
- Accepts both numeric IDs and full anime names with spaces
- Automatically searches AniList if name is provided
- Auto-detects movies and plays them regardless of episode parameter
- Sub/dub aware:
?type=dubonly returns dubbed streams (404 with a hint if none exist) - Manual pick:
?provider=aninekotries that provider first, falls back to the race (response showsrequestedProvidervs actualprovider) - Response includes
provider(winner),defaultProvider(fastest on record),streams,subtitles - Returns HLS/MP4/DASH streams with referer headers where required
- Legacy Miruro pipe is kept as a last-resort fallback
Examples:
# Using AniList ID (subbed)
curl "http://127.0.0.1:8000/anime/extract/21?e=1"
# Dubbed
curl "http://127.0.0.1:8000/anime/extract/21?e=1&type=dub"
# Manual provider pick
curl "http://127.0.0.1:8000/anime/extract/21?e=1&provider=reanime"
# Using anime name (spaces work)
curl "http://127.0.0.1:8000/anime/extract/violet%20evergarden?e=1"
# Using hyphenated name
curl "http://127.0.0.1:8000/anime/extract/my-hero-academia?e=5"
# Movie (episode param ignored)
curl "http://127.0.0.1:8000/anime/extract/a-silent-voice"Tip: If search by name fails, use /anime/search?query=<name> to get the exact AniList ID first.
Live provider ranking, availability and measured latency. (/anime/bridge-status is a deprecated alias.)
Example:
curl "http://127.0.0.1:8000/anime/providers/status"
# → { defaultProvider: "anineko", ranking: [...], available: [...], latency: { anineko: { avg_seconds, failures } } }All ports are pure Python (src/providers/, httpx only). Tested 10/09/2026 on Naruto (220 eps), One Piece and Demon Slayer:
| Provider | Episodes | Watch | Audio | Notes |
|---|---|---|---|---|
| anineko | ✅ 220 | ✅ 19 HLS | sub + dub | Fast, reliable default |
| anizone | ✅ 220 | ✅ HLS + subs | sub (dub empty upstream) | Livewire pagination |
| anikoto | ✅ 220 | ✅ 6-8 HLS | sub + dub | MegaPlay AES decrypt |
| reanime | ✅ 220 | ✅ HLS (flixcloud) | sub + dub | WASM-transform decrypt |
| aniwaves | ✅ 220 | ✅ HLS + embeds | sub + dub | vidplay/datasv/megaplay |
| kaa | ✅ 220 | ✅ HLS | sub + dub | JSON API |
| anibd | ✅ 220 | ✅ HLS + embed | sub (dub empty upstream) | AniList-keyed API |
| animegg | ✅ 220 | ✅ MP4 + embed | sub + dub | HTML scrape |
| mkissa | ✅ 440 | ✅ HLS + direct | sub + dub + raw | allanime backend |
| animeonsen | ✅ 26 | ✅ DASH | sub only | Needs modern Chrome UA |
Skipped: 2dhive (partial library, embed-only), anidbapp / animenosub / senshi / animedunya (no results on test titles).
Proxy M3U8 playlists with referer injection and URL rewriting.
Parameters:
url(string, required) - M3U8 playlist URLreferer(string, required) - Referer header value
Proxy video segments with referer injection.
Parameters:
url(string, required) - Segment URLreferer(string, required) - Referer header value
- Search for anime:
curl "http://127.0.0.1:8000/anime/search?query=demon%20slayer"- Get anime info (use ID from search):
curl "http://127.0.0.1:8000/anime/info/101922"- Get episodes:
curl "http://127.0.0.1:8000/anime/episodes/101922"- Extract streaming source:
curl "http://127.0.0.1:8000/anime/extract/101922?e=1"Skip all steps and directly extract:
# By name
curl "http://127.0.0.1:8000/anime/extract/demon%20slayer?e=1"
# By ID
curl "http://127.0.0.1:8000/anime/extract/101922?e=1"All endpoints return JSON with consistent structure:
{
"page": 1,
"perPage": 20,
"total": 1000,
"hasNextPage": true,
"results": [...]
}{
"anilistId": 21,
"episode": 1,
"type": "sub",
"provider": "anineko",
"defaultProvider": "anineko",
"streams": [
{
"type": "hls",
"url": "https://..../master.m3u8",
"server": "AniNeko",
"audio": "sub",
"referer": "https://..."
}
],
"subtitles": [...]
}Stream type is one of hls | mp4 | dash | embed (embeds need a client-side player or extractor).
Edit src/config.py to customize:
- AniList API URL
- Miruro pipe URL (legacy fallback)
- Request headers
- Timeouts
Tune the race in src/providers/_race.py:
RANKING- initial provider order (latency table takes over at runtime)WATCH_TIMEOUT/EPISODES_TIMEOUT- per-provider timeoutsWATCH_CACHE_TTL- short cache for tokenized stream URLs
- FastAPI - Modern async web framework
- httpx - Async HTTP client
- HLS.js - Video player for web interface
- AniList GraphQL API - Anime metadata
- Native providers - Pure-Python scrapers + extractors (
src/providers/) - Miruro Pipe - Legacy fallback for streaming sources
Run in development mode with auto-reload:
uvicorn api:app --reload- All image URLs are automatically proxied through serveproxy.com
- Provider priority is dynamic: fastest measured latency wins (see
/anime/providers/status) ?type=dubfilters to dubbed streams; dub lists are empty where upstream has none- Movies automatically default to episode 1
- M3U8 playlists and segments are proxied to bypass referer checks
- CORS is enabled for all origins
Educational purposes only. Respect content creators and copyright laws.
Built with ❤️ for the anime community