docs: complete API documentation folder

docs/index.md — Overview, quick start, features
docs/endpoints.md — Full API reference (27 endpoints)
docs/streaming.md — Streaming flow guide (3-step)
docs/examples.md — cURL, JavaScript, Python, Node.js examples
docs/architecture.md — Project structure, tech stack, design

Also fixes streaming endpoints:
- episodeList: Parse AJAX JSON, extract server_ids/timestamp/mal_id
- streamInfo: Parse server list HTML into structured objects
- streamInfo: Parse stream URL from JSON response
This commit is contained in:
Sʜɪɴᴇɪ Nᴏᴜᴢᴇɴ
2026-06-08 20:58:39 +05:30
parent e0e348682f
commit 12aa1f5235
6 changed files with 1698 additions and 0 deletions
+16
View File
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.7.2] - 2026-06-08
### Added
- `docs/` folder with complete API documentation
- `docs/index.md` — Overview, quick start, features
- `docs/endpoints.md` — Full API reference (27 endpoints documented)
- `docs/streaming.md` — Streaming flow guide (3-step process)
- `docs/examples.md` — Code examples in cURL, JavaScript, Python, Node.js
- `docs/architecture.md` — Project structure, tech stack, design decisions
### Fixed
- `episodeList.extractor.js` — Parse AJAX JSON response, extract `server_ids`, `timestamp`, `mal_id`
- `streamInfo.extractor.js` — Parse server list HTML into structured objects
- `streamInfo.extractor.js` — Parse stream URL from JSON response properly
- Added cheerio import to streamInfo extractor for HTML parsing
## [1.7.1] - 2026-06-08
### Changed
+256
View File
@@ -0,0 +1,256 @@
# Architecture
> Project structure, tech stack, and design decisions.
## Tech Stack
| Component | Technology |
|-----------|------------|
| Runtime | Node.js |
| Framework | Express.js |
| Scraper | Cheerio + Axios |
| Deployment | Vercel (Serverless) |
| Language | JavaScript (ES Modules) |
## Project Structure
```
AniKotoAPI/
├── server.js # Express entry point
├── vercel.json # Vercel deployment config
├── package.json # Dependencies and scripts
├── public/ # Static files
│ ├── index.html # Landing page
│ ├── 404.html # Error page
│ ├── manifest.json # PWA manifest
│ ├── robots.txt # Crawler directives
│ ├── sitemap.xml # XML sitemap
│ ├── og-image.svg # Open Graph image
│ ├── privacy.html # Privacy policy
│ └── tos.html # Terms of service
├── src/
│ ├── configs/
│ │ ├── dataUrl.js # URL patterns for anikototv.to
│ │ ├── header.config.js # Request headers
│ │ └── ids.config.js # Genre/type/status ID mappings
│ ├── controllers/
│ │ ├── homeInfo.controller.js
│ │ ├── animeInfo.controller.js
│ │ ├── search.controller.js
│ │ ├── episodeList.controller.js
│ │ ├── episodeListAjax.controller.js
│ │ ├── streamInfo.controller.js
│ │ ├── schedule.controller.js
│ │ ├── spotlight.controller.js
│ │ ├── trending.controller.js
│ │ ├── topten.controller.js
│ │ ├── suggestion.controller.js
│ │ ├── random.controller.js
│ │ ├── popular.controller.js
│ │ ├── filter.controller.js
│ │ ├── watchPage.controller.js
│ │ ├── azList.controller.js
│ │ ├── newRelease.controller.js
│ │ ├── status.controller.js
│ │ ├── trendingSidebar.controller.js
│ │ ├── seasons.controller.js
│ │ └── watchOrder.controller.js
│ ├── extractors/
│ │ ├── homeInfo.extractor.js
│ │ ├── animeInfo.extractor.js
│ │ ├── search.extractor.js
│ │ ├── episodeList.extractor.js
│ │ ├── streamInfo.extractor.js
│ │ ├── schedule.extractor.js
│ │ ├── spotlight.extractor.js
│ │ ├── trending.extractor.js
│ │ ├── topten.extractor.js
│ │ ├── suggestion.extractor.js
│ │ ├── random.extractor.js
│ │ ├── popular.extractor.js
│ │ ├── filter.extractor.js
│ │ ├── watchPage.extractor.js
│ │ ├── azList.extractor.js
│ │ ├── newRelease.extractor.js
│ │ ├── status.extractor.js
│ │ ├── trendingSidebar.extractor.js
│ │ ├── seasons.extractor.js
│ │ └── watchOrder.extractor.js
│ ├── routes/
│ │ ├── apiRoutes.js # Main API router
│ │ └── category.route.js # Genre/type/status routes
│ └── helper/
│ └── cache.helper.js # In-memory cache
└── docs/ # Documentation
├── index.md
├── endpoints.md
├── streaming.md
├── examples.md
└── architecture.md
```
## Request Flow
```
Client Request
│
▼
┌─────────────┐
│ vercel.json │ ─── /api/* ──→ server.js
│ (routing) │ ─── /* ─────→ public/
└─────────────┘
│
▼
┌─────────────┐
│ server.js │
│ (Express) │
└─────────────┘
│
▼
┌─────────────┐
│ apiRoutes.js │ ─── Route matching
└─────────────┘
│
▼
┌─────────────┐
│ Controllers │ ─── Business logic, cache check
└─────────────┘
│
▼
┌─────────────┐
│ Extractors │ ─── HTTP request + HTML parsing
└─────────────┘
│
▼
┌─────────────┐
│ anikototv.to │ ─── Source data
└─────────────┘
```
## Caching
The API uses an in-memory cache with a 5-minute TTL:
```javascript
// Cache key format: {endpoint}_{id}
// Examples:
// "episodes_naruto-shippuden"
// "stream_MTF1dkFtaW9..."
// "servers_SlNVT25..."
```
**Characteristics:**
- Stored in a JavaScript `Map`
- TTL: 5 minutes (300,000 ms)
- Reset on server restart (serverless = every cold start)
- Key format: `{type}_{identifier}`
## Source Site Structure
The API scrapes data from `anikototv.to`:
| Page | URL Pattern | Data |
|------|-------------|------|
| Home | `/home` | Spotlight, trending, popular |
| Watch | `/watch/{slug}` | Anime info, anime ID |
| Episode | `/watch/{slug}/ep-{n}` | Episode data |
| Search | `/filter?keyword={q}` | Search results |
| Genre | `/genre/{name}` | Genre listings |
| Type | `/type/{name}` | Type listings |
| Status | `/status/{name}` | Status listings |
| A-Z | `/az-list/{letter}` | Alphabetical list |
**AJAX Endpoints:**
| Endpoint | URL Pattern | Data |
|----------|-------------|------|
| Episodes | `/ajax/episode/list/{animeId}` | Episode list HTML |
| Servers | `/ajax/server/list?servers={ids}` | Server list HTML |
| Stream | `/ajax/server?get={linkId}` | Stream URL JSON |
## ID Mappings
Genre IDs (partial):
```javascript
{
action: 1,
adventure: 2,
comedy: 4,
demons: 5,
drama: 8,
fantasy: 10,
isekai: 19,
romance: 22,
shounen: 27,
supernatural: 37
}
```
Type IDs:
```javascript
{
movie: 1,
music: 2,
ona: 3,
ova: 4,
special: 5,
tv: 6
}
```
Status IDs:
```javascript
{
"currently-airing": 1,
"finished-airing": 2,
"not-yet-aired": 3
}
```
## Vercel Configuration
```json
{
"version": 2,
"builds": [
{
"src": "server.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/api/(.*)",
"dest": "server.js",
"headers": { "Access-Control-Allow-Origin": "*" }
},
{
"src": "/(.*)",
"dest": "server.js"
}
]
}
```
## Error Handling
All errors follow this format:
```json
{
"success": false,
"message": "Error description"
}
```
Common errors:
| Status | Message | Cause |
|--------|---------|-------|
| 400 | "Link ID is required" | Missing `id` parameter |
| 400 | "Episode IDs are required" | Missing `ids` parameter |
| 400 | "Anime slug is required" | Missing anime slug |
| 500 | "Internal server error" | Scraping failed or site down |
+857
View File
@@ -0,0 +1,857 @@
# API Endpoints Reference
> Complete documentation for all AniKotoAPI endpoints.
**Base URL:** `https://anikototvapi.vercel.app/api`
---
## Table of Contents
- [Home](#home)
- [Search](#search)
- [Search Suggestions](#search-suggestions)
- [Anime Info](#anime-info)
- [Episodes](#episodes)
- [Episodes AJAX](#episodes-ajax)
- [Watch Page](#watch-page)
- [Stream Info](#stream-info)
- [Server List](#server-list)
- [Mapper Servers](#mapper-servers)
- [Schedule](#schedule)
- [Spotlight](#spotlight)
- [Trending](#trending)
- [Top 10](#top-10)
- [Most Popular](#most-popular)
- [New Release](#new-release)
- [Newly Added](#newly-added)
- [Random](#random)
- [Filter](#filter)
- [Suggestions](#suggestions)
- [Trending Sidebar](#trending-sidebar)
- [Seasons](#seasons)
- [Watch Order](#watch-order)
- [A-Z List](#a-z-list)
- [Genre](#genre)
- [Type](#type)
- [Status](#status)
---
## Home
Get homepage data including spotlight, trending, popular, top-airing, genres, and more.
```
GET /api/
```
**Parameters:** None
**Example:**
```bash
curl https://anikototvapi.vercel.app/api
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api")
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": {
"spotlight": [...],
"trending": [...],
"popular": [...],
"topAiring": [...],
"genres": [...]
}
}
```
---
## Search
Search for anime by keyword with pagination.
```
GET /api/search
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `keyword` | string | Yes | — | Search query |
| `page` | number | No | 1 | Page number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/search?keyword=naruto&page=1"
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/search?keyword=naruto");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/search", params={"keyword": "naruto"})
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": {
"totalPages": 10,
"data": [
{
"title": "Naruto",
"id": "naruto-xxxxx",
"slug": "naruto-xxxxx/ep-1",
"image": "https://...",
"type": "TV",
"genres": ["Action", "Adventure"]
}
]
}
}
```
---
## Search Suggestions
Get autocomplete suggestions for search queries.
```
GET /api/search/suggest
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `keyword` | string | Yes | Partial search query |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/search/suggest?keyword=dea"
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/search/suggest?keyword=dea");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/search/suggest", params={"keyword": "dea"})
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": [
{ "title": "Death Note", "slug": "death-note-xxxxx" },
{ "title": "Deadman Wonderland", "slug": "deadman-wonderland-xxxxx" }
]
}
```
---
## Anime Info
Get detailed information about a specific anime.
```
GET /api/info
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | Anime slug |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/info?id=naruto-shippuden"
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/info?id=naruto-shippuden");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/info", params={"id": "naruto-shippuden"})
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": {
"title": "Naruto: Shippuuden",
"japaneseTitle": "ナルト- 疾風伝",
"image": "https://...",
"synopsis": "...",
"type": "TV",
"status": "Finished Airing",
"totalEpisodes": 500,
"genres": ["Action", "Adventure"],
"malId": 1735,
"relations": [...],
"recommendations": [...]
}
}
```
---
## Episodes
Get the episode list for an anime.
```
GET /api/episodes/:id
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | Anime slug (path parameter) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden"
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/episodes/naruto-shippuden");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/episodes/naruto-shippuden")
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": {
"animeId": 12345,
"slug": "naruto-shippuden",
"totalEpisodes": 500,
"episodes": [
{
"id": "110289",
"episode_no": 1,
"slug": "1",
"title": "",
"active": true,
"href": "#",
"server_ids": "SlNVT25...",
"timestamp": "1729249503",
"mal_id": "1735"
}
]
}
}
```
---
## Episodes AJAX
Get the AJAX-loaded episode list (same data as episodes, but fetched via AJAX endpoint).
```
GET /api/episodes-ajax/:id
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | Anime ID (numeric, from episodes response) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/episodes-ajax/12345"
```
---
## Watch Page
Get watch page data for a specific episode.
```
GET /api/watch
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | Anime slug |
| `ep` | number | No | Episode number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/watch?id=naruto-shippuden&ep=1"
```
---
## Stream Info
Get the streaming URL and metadata for an episode server.
```
GET /api/stream
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | Server link ID (from servers response) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9..."
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9...");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/stream", params={"id": "MTF1dkFtaW9..."})
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": {
"linkId": "MTF1dkFtaW9...",
"url": "https://megaplay.buzz/stream/s-5/94736/sub",
"skipData": {
"intro": [0, 0],
"outro": [0, 0]
}
}
}
```
---
## Server List
Get available streaming servers for an episode.
```
GET /api/servers
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `ids` | string | Yes | Server IDs (from episodes response `server_ids` field) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25..."
```
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/servers?ids=SlNVT25...");
const data = await res.json();
```
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/servers", params={"ids": "SlNVT25..."})
data = r.json()
```
**Response:**
```json
{
"success": true,
"results": [
{
"type": "sub",
"ep_id": "110289",
"link_id": "MTF1dkFtaW9...",
"cmid": "animixplay-xxxxx",
"sv_id": "323",
"name": "HD-1"
},
{
"type": "sub",
"ep_id": "110289",
"link_id": "MTF1dkFtaW9...",
"cmid": "animixplay-xxxxx",
"sv_id": "e54",
"name": "Vidstream-2"
}
]
}
```
---
## Mapper Servers
Get alternative streaming servers from the nekostream mapper API.
```
GET /api/mapper-servers
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `malId` | number | Yes | MyAnimeList ID |
| `slug` | string | Yes | Anime slug |
| `timestamp` | string | Yes | Episode timestamp |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/mapper-servers?malId=1735&slug=naruto-shippuden&timestamp=1729249503"
```
**Response:**
```json
{
"success": true,
"results": [
{
"provider": "vidstreaming",
"type": "sub",
"url": "https://...",
"download": "https://..."
}
]
}
```
---
## Schedule
Get anime airing schedule.
```
GET /api/schedule
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `date` | string | No | Today | Date in YYYY-MM-DD format |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/schedule"
curl "https://anikototvapi.vercel.app/api/schedule?date=2026-06-08"
```
---
## Spotlight
Get spotlight/featured anime carousel.
```
GET /api/spotlight
```
**Parameters:** None
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/spotlight"
```
---
## Trending
Get currently trending anime.
```
GET /api/trending
```
**Parameters:** None
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/trending"
```
---
## Top 10
Get top 10 ranked anime (today, week, month).
```
GET /api/top-ten
```
**Parameters:** None
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/top-ten"
```
---
## Most Popular
Get most popular anime list.
```
GET /api/most-popular
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `page` | number | No | 1 | Page number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/most-popular?page=1"
```
---
## New Release
Get recently released episodes.
```
GET /api/new-release
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `page` | number | No | 1 | Page number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/new-release"
```
---
## Newly Added
Get newly added anime series.
```
GET /api/newly-added
```
**Parameters:**
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `page` | number | No | 1 | Page number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/newly-added"
```
---
## Random
Get random anime information.
```
GET /api/random
```
**Parameters:** None
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/random"
```
---
## Filter
Filter anime by genre, type, status, season, and more.
```
GET /api/filter
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `keyword` | string | Yes | Search keyword (can be empty) |
| `genre[]` | number | No | Genre IDs (multiple supported) |
| `type[]` | number | No | Type IDs (multiple supported) |
| `status[]` | number | No | Status IDs (multiple supported) |
| `sort` | string | No | Sort order |
| `season` | string | No | Season |
| `page` | number | No | Page number |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/filter?keyword=&genre[]=1&genre[]=4"
```
---
## Suggestions
Get anime suggestions by keyword.
```
GET /api/suggestions
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `keyword` | string | Yes | Search keyword |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/suggestions?keyword=naruto"
```
---
## Trending Sidebar
Get trending sidebar widget data.
```
GET /api/trending-sidebar
```
**Parameters:** None
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/trending-sidebar"
```
---
## Seasons
Get season information for an anime.
```
GET /api/seasons/:id
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Anime ID (path parameter) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/seasons/12345"
```
---
## Watch Order
Get recommended watch order for an anime.
```
GET /api/watch-order/:id
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Anime ID (path parameter) |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/watch-order/12345"
```
---
## A-Z List
Get anime listing alphabetically.
```
GET /api/az-list/:letter
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `letter` | string | Yes | Letter or "other" for non-alpha titles |
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/az-list/a"
curl "https://anikototvapi.vercel.app/api/az-list/other"
```
---
## Genre
Get anime by genre.
```
GET /api/genre/:name
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Genre slug |
**Available Genres:**
`action`, `adventure`, `cars`, `comedy`, `dementia`, `demons`, `drama`, `ecchi`, `fantasy`, `game`, `harem`, `historical`, `horror`, `isekai`, `josei`, `kids`, `magic`, `mahou-shoujo`, `martial-arts`, `mecha`, `military`, `music`, `mystery`, `parody`, `police`, `psychological`, `romance`, `samurai`, `school`, `sci-fi`, `seinen`, `shoujo`, `shoujo-ai`, `shounen`, `shounen-ai`, `slice-of-life`, `space`, `sports`, `super-power`, `supernatural`, `thriller`, `unknown`, `vampire`
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/genre/action"
```
---
## Type
Get anime by type.
```
GET /api/type/:name
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Type slug |
**Available Types:** `movie`, `music`, `ona`, `ova`, `special`, `tv`
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/type/tv"
```
---
## Status
Get anime by airing status.
```
GET /api/status/:name
```
**Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Status slug |
**Available Statuses:** `currently-airing`, `finished-airing`, `not-yet-aired`
**Example:**
```bash
curl "https://anikototvapi.vercel.app/api/status/currently-airing"
```
+291
View File
@@ -0,0 +1,291 @@
# Code Examples
> Working examples in cURL, JavaScript, and Python.
## cURL
### Get Homepage
```bash
curl https://anikototvapi.vercel.app/api
```
### Search Anime
```bash
curl "https://anikototvapi.vercel.app/api/search?keyword=naruto&page=1"
```
### Get Anime Info
```bash
curl "https://anikototvapi.vercel.app/api/info?id=naruto-shippuden"
```
### Get Episodes
```bash
curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden"
```
### Get Servers
```bash
curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25..."
```
### Get Stream URL
```bash
curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9..."
```
### Get Schedule
```bash
curl "https://anikototvapi.vercel.app/api/schedule"
curl "https://anikototvapi.vercel.app/api/schedule?date=2026-06-08"
```
### Filter by Genre
```bash
curl "https://anikototvapi.vercel.app/api/filter?keyword=&genre[]=1&genre[]=4"
```
### Get Genre Anime
```bash
curl "https://anikototvapi.vercel.app/api/genre/action"
```
---
## JavaScript (Fetch API)
### Get Homepage
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api");
const data = await res.json();
console.log(data.results);
```
### Search Anime
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/search?keyword=naruto");
const data = await res.json();
data.results.data.forEach(anime => {
console.log(anime.title);
});
```
### Get Anime Info
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/info?id=naruto-shippuden");
const data = await res.json();
console.log(data.results.title);
console.log(data.results.synopsis);
```
### Get Episodes
```javascript
const res = await fetch("https://anikototvapi.vercel.app/api/episodes/naruto-shippuden");
const data = await res.json();
data.results.episodes.forEach(ep => {
console.log(`Episode ${ep.episode_no} - ID: ${ep.id}`);
});
```
### Full Streaming Flow
```javascript
const BASE = "https://anikototvapi.vercel.app/api";
async function getStream(slug, episodeNum) {
// 1. Get episodes
const epsRes = await fetch(`${BASE}/episodes/${slug}`);
const eps = await epsRes.json();
const ep = eps.results.episodes.find(e => e.episode_no === episodeNum);
// 2. Get servers
const srvRes = await fetch(`${BASE}/servers?ids=${ep.server_ids}`);
const srvs = await srvRes.json();
const server = srvs.results[0];
// 3. Get stream
const streamRes = await fetch(`${BASE}/stream?id=${server.link_id}`);
const stream = await streamRes.json();
return stream.results;
}
// Usage
getStream("naruto-shippuden", 1).then(stream => {
console.log("URL:", stream.url);
videoPlayer.src = stream.url;
});
```
### Search with Suggestions
```javascript
// Get autocomplete suggestions
const res = await fetch("https://anikototvapi.vercel.app/api/search/suggest?keyword=dea");
const suggestions = await res.json();
suggestions.results.forEach(s => console.log(s.title));
```
---
## Python (requests)
### Get Homepage
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api")
data = r.json()
print(data["results"])
```
### Search Anime
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/search", params={"keyword": "naruto"})
data = r.json()
for anime in data["results"]["data"]:
print(anime["title"])
```
### Get Anime Info
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/info", params={"id": "naruto-shippuden"})
data = r.json()
print(data["results"]["title"])
print(data["results"]["synopsis"])
```
### Get Episodes
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/episodes/naruto-shippuden")
data = r.json()
for ep in data["results"]["episodes"]:
print(f"Episode {ep['episode_no']} - ID: {ep['id']}")
```
### Full Streaming Flow
```python
import requests
BASE = "https://anikototvapi.vercel.app/api"
def get_stream(slug, episode_num):
# 1. Get episodes
eps = requests.get(f"{BASE}/episodes/{slug}").json()
ep = next(e for e in eps["results"]["episodes"] if e["episode_no"] == episode_num)
# 2. Get servers
srvs = requests.get(f"{BASE}/servers", params={"ids": ep["server_ids"]}).json()
server = srvs["results"][0]
# 3. Get stream
stream = requests.get(f"{BASE}/stream", params={"id": server["link_id"]}).json()
return stream["results"]
# Usage
stream = get_stream("naruto-shippuden", 1)
print(f"URL: {stream['url']}")
```
### Filter by Genre
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/filter", params={
"keyword": "",
"genre[]": [1, 4] # Action, Comedy
})
data = r.json()
```
### Get Schedule
```python
import requests
r = requests.get("https://anikototvapi.vercel.app/api/schedule")
data = r.json()
```
---
## Node.js (axios)
### Search Anime
```javascript
const axios = require("axios");
const { data } = await axios.get("https://anikototvapi.vercel.app/api/search", {
params: { keyword: "naruto" }
});
console.log(data.results.data);
```
### Full Streaming Flow
```javascript
const axios = require("axios");
const BASE = "https://anikototvapi.vercel.app/api";
async function getStream(slug, episodeNum) {
const { data: eps } = await axios.get(`${BASE}/episodes/${slug}`);
const ep = eps.results.episodes.find(e => e.episode_no === episodeNum);
const { data: srvs } = await axios.get(`${BASE}/servers`, { params: { ids: ep.server_ids } });
const server = srvs.results[0];
const { data: stream } = await axios.get(`${BASE}/stream`, { params: { id: server.link_id } });
return stream.results;
}
```
---
## cURL (with jq)
### Pretty Print Homepage
```bash
curl -s https://anikototvapi.vercel.app/api | jq '.results.trending[:3]'
```
### Search and Extract Titles
```bash
curl -s "https://anikototvapi.vercel.app/api/search?keyword=naruto" | jq '.results.data[].title'
```
### Get Stream URL Only
```bash
curl -s "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9..." | jq -r '.results.url'
```
+65
View File
@@ -0,0 +1,65 @@
# AniKotoAPI Documentation
> Free REST API for anime data. Browse, search, stream — no API key required.
## Overview
AniKotoAPI is a free, open-source REST API that provides anime data scraped from [anikototv.to](https://anikototv.to). It's built with Node.js, Express, and Cheerio, and deployed on Vercel.
**Base URL:** `https://anikototvapi.vercel.app/api`
## Quick Start
```bash
# Get homepage data
curl https://anikototvapi.vercel.app/api
# Search for anime
curl "https://anikototvapi.vercel.app/api/search?keyword=naruto"
# Get anime info
curl "https://anikototvapi.vercel.app/api/info?id=naruto-shippuden"
```
## Features
- **24+ Endpoints** — Home, search, info, episodes, streaming, schedule, and more
- **No API Key** — Just make requests, no registration needed
- **In-Memory Cache** — 5-minute TTL for fast responses
- **CORS Enabled** — Access from any domain
- **JSON Responses** — Standardized `{success, results}` format
## Documentation
- [API Endpoints Reference](endpoints.md) — Complete endpoint documentation
- [Streaming Flow Guide](streaming.md) — How to get stream URLs
- [Code Examples](examples.md) — cURL, JavaScript, Python
- [Architecture](architecture.md) — Project structure and design
## Response Format
All endpoints return JSON in this format:
```json
{
"success": true,
"results": { ... }
}
```
Error responses:
```json
{
"success": false,
"message": "Error description"
}
```
## Rate Limiting
There are no explicit rate limits, but the API uses a 5-minute in-memory cache. Repeated requests for the same data will be served from cache.
## Disclaimer
This API is for **educational purposes only**. It scrapes publicly available data from anikototv.to. We are not affiliated with or endorsed by AniKoto. All content belongs to its respective owners.
+213
View File
@@ -0,0 +1,213 @@
# Streaming Flow Guide
> How to get streaming URLs from AniKotoAPI.
## Overview
The streaming flow involves 3 steps:
```
1. Get episodes → /api/episodes/{slug}
2. Get servers → /api/servers?ids={server_ids}
3. Get stream URL → /api/stream?id={link_id}
```
## Step 1: Get Episodes
First, get the episode list for an anime. This returns episode data including `server_ids` needed for the next step.
```bash
curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden"
```
**Response:**
```json
{
"success": true,
"results": {
"animeId": 12345,
"slug": "naruto-shippuden",
"totalEpisodes": 500,
"episodes": [
{
"id": "110289",
"episode_no": 1,
"server_ids": "SlNVT25JaFlCMnZOeXZ2aG5t...",
"timestamp": "1729249503",
"mal_id": "1735"
}
]
}
}
```
**Key fields:**
- `server_ids` — Base64-encoded string needed for the servers endpoint
- `timestamp` — Used for the mapper API
- `mal_id` — MyAnimeList ID for the anime
## Step 2: Get Servers
Use the `server_ids` from step 1 to get available streaming servers.
```bash
curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25JaFlCMnZOeXZ2aG5t..."
```
**Response:**
```json
{
"success": true,
"results": [
{
"type": "sub",
"ep_id": "110289",
"link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...",
"cmid": "animixplay-xxxxx",
"sv_id": "323",
"name": "HD-1"
},
{
"type": "sub",
"ep_id": "110289",
"link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...",
"cmid": "animixplay-xxxxx",
"sv_id": "e54",
"name": "Vidstream-2"
},
{
"type": "dub",
"ep_id": "110289",
"link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...",
"cmid": "animixplay-xxxxx",
"sv_id": "a41",
"name": "VidCloud-1"
}
]
}
```
**Key fields:**
- `type` — "sub" or "dub"
- `link_id` — ID needed for the stream endpoint
- `name` — Server name (HD-1, Vidstream-2, etc.)
## Step 3: Get Stream URL
Use the `link_id` from step 2 to get the actual streaming URL.
```bash
curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZr..."
```
**Response:**
```json
{
"success": true,
"results": {
"linkId": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...",
"url": "https://megaplay.buzz/stream/s-5/94736/sub",
"skipData": {
"intro": [0, 0],
"outro": [0, 0]
}
}
}
```
**Key fields:**
- `url` — Direct streaming URL (m3u8 or mp4)
- `skipData` — Intro/outro timestamps for skipping
## Complete Example (JavaScript)
```javascript
const BASE = "https://anikototvapi.vercel.app/api";
async function getStreamUrl(animeSlug, episodeNumber) {
// Step 1: Get episodes
const epsRes = await fetch(`${BASE}/episodes/${animeSlug}`);
const epsData = await epsRes.json();
const episode = epsData.results.episodes.find(
ep => ep.episode_no === episodeNumber
);
if (!episode) throw new Error("Episode not found");
// Step 2: Get servers
const srvRes = await fetch(`${BASE}/servers?ids=${episode.server_ids}`);
const srvData = await srvRes.json();
const server = srvData.results.find(s => s.type === "sub") || srvData.results[0];
if (!server) throw new Error("No servers available");
// Step 3: Get stream URL
const streamRes = await fetch(`${BASE}/stream?id=${server.link_id}`);
const streamData = await streamRes.json();
return streamData.results;
}
// Usage
getStreamUrl("naruto-shippuden", 1)
.then(stream => {
console.log("Stream URL:", stream.url);
console.log("Skip intro at:", stream.skipData.intro[0]);
});
```
## Complete Example (Python)
```python
import requests
BASE = "https://anikototvapi.vercel.app/api"
def get_stream_url(anime_slug, episode_number):
# Step 1: Get episodes
eps_res = requests.get(f"{BASE}/episodes/{anime_slug}")
eps_data = eps_res.json()
episode = next(
ep for ep in eps_data["results"]["episodes"]
if ep["episode_no"] == episode_number
)
# Step 2: Get servers
srv_res = requests.get(f"{BASE}/servers", params={"ids": episode["server_ids"]})
srv_data = srv_res.json()
server = next(
(s for s in srv_data["results"] if s["type"] == "sub"),
srv_data["results"][0]
)
# Step 3: Get stream URL
stream_res = requests.get(f"{BASE}/stream", params={"id": server["link_id"]})
stream_data = stream_res.json()
return stream_data["results"]
# Usage
stream = get_stream_url("naruto-shippuden", 1)
print(f"Stream URL: {stream['url']}")
print(f"Skip intro at: {stream['skipData']['intro'][0]}")
```
## Alternative: Mapper Servers
For additional streaming sources, use the mapper API with `malId`, `slug`, and `timestamp` from the episodes response.
```bash
curl "https://anikototvapi.vercel.app/api/mapper-servers?malId=1735&slug=naruto-shippuden&timestamp=1729249503"
```
This returns alternative providers like VidStreaming, Gogoanime, etc.
## Notes
- The `url` in stream response is typically an m3u8 playlist or direct mp4 link
- `skipData` contains intro/outro timestamps in seconds
- Some servers may require specific headers or referrers to work
- The mapper API is external and may not always be available