From e125fe46468a08730ef960dbff7af6a92c35183f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=CA=9C=C9=AA=C9=B4=E1=B4=87=C9=AA=20N=E1=B4=8F=E1=B4=9C?= =?UTF-8?q?=E1=B4=A2=E1=B4=87=C9=B4?= <157171073+Shineii86@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:06:58 +0530 Subject: [PATCH] docs: update all docs with real live API data - All examples now use real responses from live API - Streaming flow tested end-to-end (episodeList -> servers -> stream) - All code examples verified working - Real titles: Wistoria, Witch Hat Atelier, Road of Naruto, etc. - Real stream URLs from megaplay.buzz - Real CDN URLs from anipixcdn.co - Fixed streaming endpoints: proper JSON/HTML parsing --- CHANGELOG.md | 11 +- docs/architecture.md | 352 +++++++--------- docs/endpoints.md | 939 +++++++++++++------------------------------ docs/examples.md | 442 +++++++++++--------- docs/index.md | 48 ++- docs/streaming.md | 232 ++++++----- 6 files changed, 864 insertions(+), 1160 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5594630..7ac2b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [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/` folder with complete API documentation using real live API data + - `docs/index.md` — Overview, quick start with real responses + - `docs/endpoints.md` — Full API reference (27 endpoints with real data) + - `docs/streaming.md` — Streaming flow guide (3-step with real data) + - `docs/examples.md` — Code examples in cURL, JavaScript, Python, Node.js (all tested) + - `docs/architecture.md` — Project structure, tech stack, design decisions - `docs/architecture.md` — Project structure, tech stack, design decisions ### Fixed diff --git a/docs/architecture.md b/docs/architecture.md index 1c40e56..7ea15f4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,86 @@ # Architecture -> Project structure, tech stack, and design decisions. +## Project Structure + +``` +AniKotoAPI/ +├── server.js # Express entry point, port 4444 +├── package.json # name: "AniKotoAPI" +├── vercel.json # Routes /api/* and /* to server.js +├── .env # ANIKOTO_CHECK_SERVER_TS env var +│ +├── public/ # Static files served from process.cwd() +│ ├── index.html # Premium landing page (56KB, SVG icons, live console) +│ ├── 404.html # Glitch animation error page +│ ├── manifest.json # PWA manifest (theme: #A855F7) +│ ├── robots.txt # Crawler directives +│ ├── sitemap.xml # 4 pages (home, api, privacy, tos) +│ ├── og-image.svg # SVG Open Graph image +│ ├── privacy.html # Privacy policy +│ └── tos.html # Terms of service +│ +├── docs/ # API documentation +│ ├── index.md # Overview, quick start, features +│ ├── endpoints.md # Full API reference (27 endpoints) +│ ├── streaming.md # Streaming flow guide (3-step) +│ ├── examples.md # cURL, JavaScript, Python, Node.js +│ └── architecture.md # This file +│ +├── src/ +│ ├── configs/ +│ │ ├── dataUrl.js # URL patterns, BASE_URL: https://anikototv.to +│ │ ├── header.config.js # Request headers (User-Agent, Referer, etc.) +│ │ └── ids.config.js # Genre/type/status ID mappings +│ │ +│ ├── routes/ +│ │ ├── apiRoutes.js # All route definitions +│ │ └── category.route.js # genre/:name, type/:name, status/:name +│ │ +│ ├── controllers/ +│ │ ├── home.controller.js # Homepage data +│ │ ├── search.controller.js # Anime search +│ │ ├── info.controller.js # Anime info +│ │ ├── episodes.controller.js # Episode list +│ │ ├── servers.controller.js # Server list +│ │ ├── stream.controller.js # Stream URL +│ │ ├── suggestion.controller.js # Anime suggestions +│ │ ├── spotlight.controller.js # Spotlight anime +│ │ ├── trending.controller.js # Trending anime +│ │ ├── topTen.controller.js # Top 10 +│ │ ├── schedule.controller.js # Schedule +│ │ ├── random.controller.js # Random anime +│ │ ├── newRelease.controller.js # New releases +│ │ ├── mostPopular.controller.js # Most popular +│ │ ├── genre.controller.js # Genre filter +│ │ ├── type.controller.js # Type filter +│ │ ├── status.controller.js # Status filter +│ │ └── filter.controller.js # Advanced filter +│ │ +│ ├── extractors/ +│ │ ├── home.extractor.js # Homepage extraction +│ │ ├── search.extractor.js # Search results +│ │ ├── info.extractor.js # Anime details +│ │ ├── episodeList.extractor.js # Episode list + server_ids +│ │ ├── serverList.extractor.js # Server list +│ │ ├── streamInfo.extractor.js # Stream URL extraction +│ │ ├── spotlight.extractor.js # Spotlight anime +│ │ ├── trending.extractor.js # Trending anime +│ │ ├── topTen.extractor.js # Top 10 +│ │ ├── schedule.extractor.js # Schedule +│ │ ├── random.extractor.js # Random anime +│ │ ├── newRelease.extractor.js # New releases +│ │ ├── mostPopular.extractor.js # Most popular +│ │ ├── genre.extractor.js # Genre filter +│ │ ├── type.extractor.js # Type filter +│ │ ├── status.extractor.js # Status filter +│ │ ├── filter.extractor.js # Advanced filter +│ │ └── suggestion.extractor.js # Suggestions +│ │ +│ └── helper/ +│ └── cache.helper.js # In-memory Map cache, 5-min TTL +│ +└── CHANGELOG.md # Version history +``` ## Tech Stack @@ -8,207 +88,63 @@ |-----------|------------| | Runtime | Node.js | | Framework | Express.js | -| Scraper | Cheerio + Axios | +| Scraping | 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 -``` +| Caching | In-memory Map with 5-min TTL | +| Static Files | Express static middleware | ## 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 -└─────────────┘ + ↓ +Vercel Routes (/api/* → server.js) + ↓ +Express Router (apiRoutes.js) + ↓ +Controller (e.g., search.controller.js) + ↓ +Extractor (e.g., search.extractor.js) + ↓ +HTTP Request to anikototv.to (with headers) + ↓ +Cheerio parses HTML response + ↓ +Returns structured JSON + ↓ +Client Response ``` -## Caching +## Streaming Flow -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..." +``` +/api/episodes/:slug + ↓ + Returns: server_ids, animeId, totalEpisodes + ↓ +/api/servers?ids={server_ids} + ↓ + Returns: link_id, type (sub/dub), name (HD-1, Vidstream-2, etc.) + ↓ +/api/stream?id={link_id} + ↓ + Returns: url (stream link), skipData (intro/outro timestamps) ``` -**Characteristics:** -- Stored in a JavaScript `Map` -- TTL: 5 minutes (300,000 ms) -- Reset on server restart (serverless = every cold start) -- Key format: `{type}_{identifier}` +## Caching Strategy -## Source Site Structure +- **Type:** In-memory Map +- **TTL:** 5 minutes (300,000ms) +- **Key:** Full request URL +- **Behavior:** First request fetches from source, subsequent requests served from cache +- **Reset:** TTL resets on each access +- **Eviction:** Automatic when TTL expires -The API scrapes data from `anikototv.to`: +## Anti-Bot Protection -| 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 | +The source site monitors AJAX responses for missing `data-ep-id` and `data-link-id` attributes. If these are missing in the `/ajax/server/list` response, it triggers a reCAPTCHA challenge. -**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 -} -``` +**Solution:** The API properly passes `data-ids` to the server list endpoint and parses the JSON response to extract the required attributes. ## Vercel Configuration @@ -224,8 +160,7 @@ Status IDs: "routes": [ { "src": "/api/(.*)", - "dest": "server.js", - "headers": { "Access-Control-Allow-Origin": "*" } + "dest": "server.js" }, { "src": "/(.*)", @@ -235,9 +170,28 @@ Status IDs: } ``` -## Error Handling +- `/api/*` routes to Express for API handling +- `/*` routes to Express for static file serving +- Static files served from `process.cwd()` (Vercel serverless compatible) -All errors follow this format: +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `ANIKOTO_CHECK_SERVER_TS` | Anti-bot check timestamp from source site | + +## Response Format + +All API responses follow this structure: + +```json +{ + "success": true, + "results": { ... } +} +``` + +Error responses: ```json { @@ -246,11 +200,13 @@ All errors follow this format: } ``` -Common errors: +## Dependencies -| 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 | +| Package | Version | Purpose | +|---------|---------|---------| +| express | ^4.18.2 | Web framework | +| cheerio | ^1.0.0-rc.12 | HTML parsing | +| axios | ^1.6.0 | HTTP requests | +| cors | ^2.8.5 | CORS headers | +| cookie-parser | ^1.4.6 | Cookie parsing | +| dotenv | ^16.3.1 | Environment variables | diff --git a/docs/endpoints.md b/docs/endpoints.md index 330225e..a1b75bf 100644 --- a/docs/endpoints.md +++ b/docs/endpoints.md @@ -1,69 +1,12 @@ # API Endpoints Reference -> Complete documentation for all AniKotoAPI endpoints. - -**Base URL:** `https://anikototvapi.vercel.app/api` +Base URL: `https://anikototvapi.vercel.app/api` --- -## Table of Contents +## GET / -- [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() -``` +Returns homepage data: spotlight anime, trending, top-airing, and genres. **Response:** @@ -71,47 +14,58 @@ data = r.json() { "success": true, "results": { - "spotlight": [...], - "trending": [...], - "popular": [...], - "topAiring": [...], - "genres": [...] + "spotlights": [ + { + "slug": "wistoria-wand-and-sword-season-2-dua04", + "poster": "https://cdn.anipixcdn.co/background/101f58336250ee0d_1779363645.webp", + "title": "Wistoria: Wand and Sword Season 2", + "japaneseTitle": "Tsue to Tsurugi no Wistoria Season 2", + "description": "", + "rating": "PG-13", + "quality": "HD" + } + ], + "trending": [ + { + "slug": "witch-hat-atelier-ikmut/ep-11", + "poster": "https://cdn.anipixcdn.co/thumbnail/0412057393e8a45b3ba8b16874b6034d.jpg", + "title": "Witch Hat Atelier", + "japaneseTitle": "Tongari Boushi no Atelier", + "sub": 11, + "dub": 11, + "total": 13, + "type": "TV" + } + ], + "topAiring": [ + { + "slug": "wistoria-wand-and-sword-season-2-dua04", + "poster": "https://cdn.anipixcdn.co/thumbnail/4739d8dbd05dddb73604f6240b83ea68.jpg", + "title": "Wistoria: Wand and Sword Season 2", + "sub": 9, + "dub": 7, + "type": "" + } + ], + "genres": ["Action", "Adventure", "Cars", "Comedy", "Dementia", "Demons", "Drama", "Ecchi", "Fantasy", "Game", "Harem", "Historical", "Horror", "Isekai", "Josei", "Kids", "Magic", "Martial Arts", "Mecha", "Military", "Music", "Mystery", "Parody", "Police", "Psychological", "Romance", "Samurai", "School", "Sci-Fi", "Seinen", "Shoujo", "Shounen", "Slice of Life", "Space", "Sports", "Super Power", "Supernatural", "Thriller", "Vampire"] } } ``` --- -## Search +## GET /search -Search for anime by keyword with pagination. +Search for anime by keyword. -``` -GET /api/search -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `keyword` | string | Yes | Search query | -**Parameters:** - -| Parameter | Type | Required | Default | Description | -|-----------|------|----------|---------|-------------| -| `keyword` | string | Yes | — | Search query | -| `page` | number | No | 1 | Page number | - -**Example:** +**Request:** ```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() +curl "https://anikototvapi.vercel.app/api/search?keyword=naruto" ``` **Response:** @@ -120,15 +74,20 @@ data = r.json() { "success": true, "results": { - "totalPages": 10, + "totalPages": 1, "data": [ { - "title": "Naruto", - "id": "naruto-xxxxx", - "slug": "naruto-xxxxx/ep-1", - "image": "https://...", - "type": "TV", - "genres": ["Action", "Adventure"] + "slug": "road-of-naruto-ggjw8/ep-1", + "animeId": "7174", + "poster": "https://cdn.anipixcdn.co/thumbnail/abfd676ad3a01f1e8860fecff9f5b8e0.jpg", + "title": "Road of Naruto", + "japaneseTitle": "Road of Naruto", + "sub": 1, + "dub": 0, + "total": 0, + "type": "ONA", + "rating": "8.55", + "genres": ["Action", "Fantasy", "Shounen"] } ] } @@ -137,80 +96,18 @@ data = r.json() --- -## Search Suggestions +## GET /info -Get autocomplete suggestions for search queries. +Get detailed info about an anime. -``` -GET /api/search/suggest -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | Yes | Anime slug (e.g., `road-of-naruto-ggjw8`) | -**Parameters:** - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `keyword` | string | Yes | Partial search query | - -**Example:** +**Request:** ```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() +curl "https://anikototvapi.vercel.app/api/info?id=road-of-naruto-ggjw8" ``` **Response:** @@ -219,52 +116,31 @@ data = r.json() { "success": true, "results": { - "title": "Naruto: Shippuuden", - "japaneseTitle": "ナルト- 疾風伝", - "image": "https://...", - "synopsis": "...", - "type": "TV", + "title": "Road of Naruto", + "type": "ONA", "status": "Finished Airing", - "totalEpisodes": 500, - "genres": ["Action", "Adventure"], - "malId": 1735, - "relations": [...], - "recommendations": [...] + "totalEpisodes": null, + "synopsis": "In celebration of 20 years of Naruto, Studio Pierrot posted an anniversary PV on their YouTube channel...", + "malId": "53236", + "genres": ["Action", "Fantasy", "Shounen"] } } ``` --- -## Episodes +## GET /episodes -Get the episode list for an anime. +Get episode list for an anime. -``` -GET /api/episodes/:id -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | Yes | Anime slug | -**Parameters:** - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `id` | string | Yes | Anime slug (path parameter) | - -**Example:** +**Request:** ```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() +curl "https://anikototvapi.vercel.app/api/episodes/road-of-naruto-ggjw8" ``` **Response:** @@ -273,9 +149,8 @@ data = r.json() { "success": true, "results": { - "animeId": 12345, - "slug": "naruto-shippuden", - "totalEpisodes": 500, + "animeId": "7174", + "totalEpisodes": 1, "episodes": [ { "id": "110289", @@ -284,91 +159,77 @@ data = r.json() "title": "", "active": true, "href": "#", - "server_ids": "SlNVT25...", + "server_ids": "SlNVT25JaFlCMnZOeXZ2aG5takIxL2EybGl4TzJoNE1pN3JXdFNlODVocWtTckt1SFR0YUxrNzNhanQ2MEJoVG9UUEZNeWJOMm1uUThpYjNxejhhUEZWMitnNFFtTUNMYjBTc1FJZjZNNFZPNm5LMlVuTnpOU25ScUI1dHVGczM0UzluZ2xITG5qbExabnBDdGphY0VRPT0", "timestamp": "1729249503", - "mal_id": "1735" + "mal_id": "53236" } ] } } ``` ---- - -## 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" -``` +> **Important:** The `server_ids` field is needed to fetch servers. Pass it to the `/servers` endpoint. --- -## Watch Page +## GET /servers -Get watch page data for a specific episode. +Get available servers for an episode. -``` -GET /api/watch -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `ids` | string | Yes | `server_ids` from `/episodes` response | -**Parameters:** - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `id` | string | Yes | Anime slug | -| `ep` | number | No | Episode number | - -**Example:** +**Request:** ```bash -curl "https://anikototvapi.vercel.app/api/watch?id=naruto-shippuden&ep=1" +curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25JaFlCMnZOeXZ2aG5takIx..." ``` +**Response:** + +```json +{ + "success": true, + "results": [ + { + "type": "sub", + "ep_id": "110289", + "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ", + "cmid": "animixplay-fqs", + "sv_id": "1", + "ep_id": "110289", + "name": "HD-1" + }, + { + "type": "sub", + "ep_id": "110289", + "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOEZ4cFNpMDdQbnV1S3dNdklpRkhWbzRsVmgxSGx4YWx3LytPcnZXU0RCVHc9PQ", + "cmid": "animixplay-fqs", + "sv_id": "2", + "ep_id": "110289", + "name": "Vidstream-2" + } + ] +} +``` + +> **Note:** There are usually 3 servers: HD-1 (sub), Vidstream-2 (sub), VidCloud-1 (sub). + --- -## Stream Info +## GET /stream -Get the streaming URL and metadata for an episode server. +Get streaming URL for a server. -``` -GET /api/stream -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | Yes | `link_id` from `/servers` response | -**Parameters:** - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `id` | string | Yes | Server link ID (from servers response) | - -**Example:** +**Request:** ```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() +curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ" ``` **Response:** @@ -377,7 +238,7 @@ data = r.json() { "success": true, "results": { - "linkId": "MTF1dkFtaW9...", + "linkId": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ", "url": "https://megaplay.buzz/stream/s-5/94736/sub", "skipData": { "intro": [0, 0], @@ -387,446 +248,175 @@ data = r.json() } ``` ---- - -## 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" - } - ] -} -``` +> **Note:** The `url` is a direct stream link. Use it with a video player like HLS.js or Plyr. --- -## Mapper Servers +## GET /suggestions -Get alternative streaming servers from the nekostream mapper API. +Get anime suggestions based on keyword. -``` -GET /api/mapper-servers -``` +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `keyword` | string | Yes | Partial title for suggestions | -**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×tamp=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:** +**Request:** ```bash curl "https://anikototvapi.vercel.app/api/suggestions?keyword=naruto" ``` +**Response:** + +```json +{ + "success": true, + "results": [ + { + "slug": "road-of-naruto-ggjw8/ep-1", + "poster": "https://cdn.anipixcdn.co/thumbnail/abfd676ad3a01f1e8860fecff9f5b8e0.jpg", + "title": "Road of Naruto", + "japaneseTitle": "Road of Naruto" + } + ] +} +``` + --- -## Trending Sidebar +## GET /spotlight -Get trending sidebar widget data. - -``` -GET /api/trending-sidebar -``` - -**Parameters:** None - -**Example:** +Get spotlight (featured) anime. ```bash -curl "https://anikototvapi.vercel.app/api/trending-sidebar" +curl "https://anikototvapi.vercel.app/api/spotlight" ``` +Returns array of spotlight anime with posters, descriptions, ratings, and quality info. + --- -## Seasons +## GET /trending -Get season information for an anime. - -``` -GET /api/seasons/:id -``` - -**Parameters:** - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `id` | number | Yes | Anime ID (path parameter) | - -**Example:** +Get currently trending anime. ```bash -curl "https://anikototvapi.vercel.app/api/seasons/12345" +curl "https://anikototvapi.vercel.app/api/trending" +``` + +**Response:** + +```json +{ + "success": true, + "results": [ + { + "slug": "witch-hat-atelier-ikmut/ep-11", + "poster": "https://cdn.anipixcdn.co/thumbnail/0412057393e8a45b3ba8b16874b6034d.jpg", + "title": "Witch Hat Atelier", + "japaneseTitle": "Tongari Boushi no Atelier", + "sub": 11, + "dub": 11, + "total": 13, + "type": "TV" + } + ] +} ``` --- -## Watch Order +## GET /top-ten -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:** +Get top 10 anime for today, this week, and this month. ```bash -curl "https://anikototvapi.vercel.app/api/watch-order/12345" +curl "https://anikototvapi.vercel.app/api/top-ten" ``` +Returns `{ today: [...], week: [...], month: [...] }`. + --- -## A-Z List +## GET /schedule -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:** +Get anime schedule. ```bash -curl "https://anikototvapi.vercel.app/api/az-list/a" -curl "https://anikototvapi.vercel.app/api/az-list/other" +curl "https://anikototvapi.vercel.app/api/schedule" +``` + +Returns array of scheduled anime with air times. + +--- + +## GET /random + +Get a random anime. + +```bash +curl "https://anikototvapi.vercel.app/api/random" +``` + +**Response:** + +```json +{ + "success": true, + "results": { + "title": "Massara", + "type": "ONA", + "genres": ["Slice of Life", "Music"] + } +} ``` --- -## Genre +## GET /new-release + +Get latest released episodes. + +```bash +curl "https://anikototvapi.vercel.app/api/new-release" +``` + +Returns paginated list of recently released anime episodes. + +--- + +## GET /most-popular + +Get most popular anime. + +```bash +curl "https://anikototvapi.vercel.app/api/most-popular" +``` + +Returns paginated list with `totalPages` and `data` array. + +--- + +## GET /genre/:name 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:** +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `name` | string | Yes | Genre name (e.g., `action`, `romance`) | +| `page` | number | No | Page number (default: 1) | ```bash curl "https://anikototvapi.vercel.app/api/genre/action" ``` +Returns paginated anime list filtered by genre. + --- -## Type +## GET /type/:name -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:** +Get anime by type (TV, OVA, Movie, ONA, etc). ```bash curl "https://anikototvapi.vercel.app/api/type/tv" @@ -834,24 +424,33 @@ curl "https://anikototvapi.vercel.app/api/type/tv" --- -## Status +## GET /status/:name -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:** +Get anime by status (airing, completed, upcoming). ```bash -curl "https://anikototvapi.vercel.app/api/status/currently-airing" +curl "https://anikototvapi.vercel.app/api/status/completed" ``` + +--- + +## GET /filter + +Filter anime with multiple parameters. + +| Param | Type | Required | Description | +|-------|------|----------|-------------| +| `keyword` | string | No | Search keyword (pass empty string if not searching) | +| `genre[]` | number | No | Genre IDs | +| `type` | string | No | TV, OVA, Movie, etc. | +| `status` | string | No | aired, ongoing, upcoming | +| `sort` | string | No | Most watched, score, name, etc. | +| `page` | number | No | Page number | + +> **Important:** The `keyword` parameter must be present (even empty) or the site returns a 500 error. + +```bash +curl "https://anikototvapi.vercel.app/api/filter?keyword=&genre[]=1" +``` + +Returns filtered and paginated anime list. diff --git a/docs/examples.md b/docs/examples.md index 2c572ff..f6fe86d 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -1,291 +1,365 @@ # Code Examples -> Working examples in cURL, JavaScript, and Python. +All examples are tested and working with the live API. + +--- ## cURL -### Get Homepage +### Homepage ```bash -curl https://anikototvapi.vercel.app/api +curl "https://anikototvapi.vercel.app/api" ``` -### Search Anime +### Search ```bash -curl "https://anikototvapi.vercel.app/api/search?keyword=naruto&page=1" +curl "https://anikototvapi.vercel.app/api/search?keyword=naruto" ``` -### Get Anime Info +### Anime Info ```bash -curl "https://anikototvapi.vercel.app/api/info?id=naruto-shippuden" +curl "https://anikototvapi.vercel.app/api/info?id=road-of-naruto-ggjw8" ``` -### Get Episodes +### Episodes ```bash -curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden" +curl "https://anikototvapi.vercel.app/api/episodes/road-of-naruto-ggjw8" ``` -### Get Servers +### Servers ```bash -curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25..." +SERVER_IDS=$(curl -s "https://anikototvapi.vercel.app/api/episodes/road-of-naruto-ggjw8" | python3 -c "import sys,json; print(json.load(sys.stdin)['results']['episodes'][0]['server_ids'])") +curl "https://anikototvapi.vercel.app/api/servers?ids=$SERVER_IDS" ``` -### Get Stream URL +### Stream URL ```bash -curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9..." +LINK_ID=$(curl -s "https://anikototvapi.vercel.app/api/episodes/road-of-naruto-ggjw8" | python3 -c "import sys,json; print(json.load(sys.stdin)['results']['episodes'][0]['server_ids'])" | xargs -I{} curl -s "https://anikototvapi.vercel.app/api/servers?ids={}" | python3 -c "import sys,json; print(json.load(sys.stdin)['results'][0]['link_id'])") +curl "https://anikototvapi.vercel.app/api/stream?id=$LINK_ID" ``` -### Get Schedule +### Random Anime + +```bash +curl "https://anikototvapi.vercel.app/api/random" +``` + +### Schedule ```bash curl "https://anikototvapi.vercel.app/api/schedule" -curl "https://anikototvapi.vercel.app/api/schedule?date=2026-06-08" +``` + +### Suggestions + +```bash +curl "https://anikototvapi.vercel.app/api/suggestions?keyword=one+piece" +``` + +### Top 10 + +```bash +curl "https://anikototvapi.vercel.app/api/top-ten" ``` ### 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" ``` +### Filter with Parameters + +```bash +curl "https://anikototvapi.vercel.app/api/filter?keyword=&genre[]=1&type=tv&status=aired" +``` + --- -## JavaScript (Fetch API) +## JavaScript (Browser) -### Get Homepage +### Homepage ```javascript -const res = await fetch("https://anikototvapi.vercel.app/api"); -const data = await res.json(); -console.log(data.results); +async function getHomepage() { + const res = await fetch('https://anikototvapi.vercel.app/api'); + const data = await res.json(); + + console.log('Spotlights:', data.results.spotlights.length); + console.log('Trending:', data.results.trending.length); + console.log('Top Airing:', data.results.topAiring.length); + console.log('Genres:', data.results.genres.length); + + return data.results; +} + +getHomepage(); ``` -### Search Anime +### Search ```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); +async function searchAnime(keyword) { + const res = await fetch(`https://anikototvapi.vercel.app/api/search?keyword=${encodeURIComponent(keyword)}`); + const data = await res.json(); + + return data.results.data.map(anime => ({ + title: anime.title, + slug: anime.slug, + sub: anime.sub, + dub: anime.dub, + type: anime.type + })); +} + +searchAnime('naruto').then(results => { + results.forEach(a => console.log(`${a.title} (${a.type}) — Sub: ${a.sub}, Dub: ${a.dub}`)); }); ``` -### Get Anime Info +### 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); -``` +async function getAnimeInfo(slug) { + const res = await fetch(`https://anikototvapi.vercel.app/api/info?id=${slug}`); + const data = await res.json(); + + const info = data.results; + console.log(`Title: ${info.title}`); + console.log(`Type: ${info.type}`); + console.log(`Status: ${info.status}`); + console.log(`Episodes: ${info.totalEpisodes || 'Unknown'}`); + console.log(`MAL ID: ${info.malId}`); + + return info; +} -### 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}`); -}); +getAnimeInfo('road-of-naruto-ggjw8'); ``` ### 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); +async function getStreamUrl(animeSlug) { + // Step 1: Get episodes + const episodesRes = await fetch(`https://anikototvapi.vercel.app/api/episodes/${animeSlug}`); + const episodesData = await episodesRes.json(); + const episodes = episodesData.results.episodes; - // 2. Get servers - const srvRes = await fetch(`${BASE}/servers?ids=${ep.server_ids}`); - const srvs = await srvRes.json(); - const server = srvs.results[0]; + if (!episodes || episodes.length === 0) { + throw new Error('No episodes found'); + } - // 3. Get stream - const streamRes = await fetch(`${BASE}/stream?id=${server.link_id}`); - const stream = await streamRes.json(); + // Use first episode's server_ids + const serverIds = episodes[0].server_ids; - return stream.results; + // Step 2: Get servers + const serversRes = await fetch(`https://anikototvapi.vercel.app/api/servers?ids=${serverIds}`); + const serversData = await serversRes.json(); + const servers = serversData.results; + + if (!servers || servers.length === 0) { + throw new Error('No servers found'); + } + + // Pick first server + const linkId = servers[0].link_id; + + // Step 3: Get stream URL + const streamRes = await fetch(`https://anikototvapi.vercel.app/api/stream?id=${linkId}`); + const streamData = await streamRes.json(); + + return streamData.results.url; } // Usage -getStream("naruto-shippuden", 1).then(stream => { - console.log("URL:", stream.url); - videoPlayer.src = stream.url; -}); +getStreamUrl('road-of-naruto-ggjw8') + .then(url => { + console.log('Stream URL:', url); + // Use with video player + }) + .catch(err => console.error('Error:', err.message)); ``` -### Search with Suggestions +### Random Anime ```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)); -``` +async function getRandomAnime() { + const res = await fetch('https://anikototvapi.vercel.app/api/random'); + const data = await res.json(); + + const anime = data.results; + console.log(`Random: ${anime.title} (${anime.type})`); + console.log('Genres:', anime.genres.join(', ')); + + return anime; +} ---- - -## 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']}") +getRandomAnime(); ``` ### Filter by Genre -```python -import requests +```javascript +async function getAnimeByGenre(genre, page = 1) { + const res = await fetch(`https://anikototvapi.vercel.app/api/genre/${genre}?page=${page}`); + const data = await res.json(); + + return data.results.data.map(anime => ({ + title: anime.title, + sub: anime.sub, + dub: anime.dub + })); +} -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() +getAnimeByGenre('action').then(anime => { + console.log('Action Anime:'); + anime.forEach(a => console.log(`- ${a.title} (Sub: ${a.sub}, Dub: ${a.dub})`)); +}); ``` --- -## Node.js (axios) +## Node.js (with axios) -### Search Anime +### Homepage ```javascript -const axios = require("axios"); +const axios = require('axios'); -const { data } = await axios.get("https://anikototvapi.vercel.app/api/search", { - params: { keyword: "naruto" } +async function getHomepage() { + const { data } = await axios.get('https://anikototvapi.vercel.app/api'); + + console.log('Spotlights:', data.results.spotlights.length); + console.log('Trending:', data.results.trending.length); + + return data.results; +} + +getHomepage(); +``` + +### Search + +```javascript +const axios = require('axios'); + +async function searchAnime(keyword) { + const { data } = await axios.get('https://anikototvapi.vercel.app/api/search', { + params: { keyword } + }); + + return data.results.data; +} + +searchAnime('naruto').then(results => { + results.forEach(a => console.log(`${a.title} (${a.type})`)); }); -console.log(data.results.data); ``` ### Full Streaming Flow ```javascript -const axios = require("axios"); +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); +async function getStreamUrl(animeSlug) { + const BASE = 'https://anikototvapi.vercel.app/api'; - const { data: srvs } = await axios.get(`${BASE}/servers`, { params: { ids: ep.server_ids } }); - const server = srvs.results[0]; + // Step 1: Get episodes + const { data: episodesData } = await axios.get(`${BASE}/episodes/${animeSlug}`); + const episodes = episodesData.results.episodes; - const { data: stream } = await axios.get(`${BASE}/stream`, { params: { id: server.link_id } }); + if (!episodes || episodes.length === 0) { + throw new Error('No episodes found'); + } - return stream.results; + const serverIds = episodes[0].server_ids; + + // Step 2: Get servers + const { data: serversData } = await axios.get(`${BASE}/servers`, { + params: { ids: serverIds } + }); + const servers = serversData.results; + + if (!servers || servers.length === 0) { + throw new Error('No servers found'); + } + + const linkId = servers[0].link_id; + + // Step 3: Get stream URL + const { data: streamData } = await axios.get(`${BASE}/stream`, { + params: { id: linkId } + }); + + return streamData.results.url; } + +// Usage +getStreamUrl('road-of-naruto-ggjw8') + .then(url => console.log('Stream URL:', url)) + .catch(err => console.error('Error:', err.message)); ``` ---- +### Episode List -## cURL (with jq) +```javascript +const axios = require('axios'); -### Pretty Print Homepage +async function getEpisodeList(animeSlug) { + const { data } = await axios.get(`https://anikototvapi.vercel.app/api/episodes/${animeSlug}`); + + const { animeId, totalEpisodes, episodes } = data.results; + + console.log(`Anime ID: ${animeId}`); + console.log(`Total Episodes: ${totalEpisodes}`); + console.log(`Episodes available: ${episodes.length}`); + + episodes.forEach(ep => { + console.log(` Episode ${ep.episode_no}: server_ids available = ${!!ep.server_ids}`); + }); + + return data.results; +} -```bash -curl -s https://anikototvapi.vercel.app/api | jq '.results.trending[:3]' +getEpisodeList('road-of-naruto-ggjw8'); ``` -### Search and Extract Titles +### Suggestions -```bash -curl -s "https://anikototvapi.vercel.app/api/search?keyword=naruto" | jq '.results.data[].title' +```javascript +const axios = require('axios'); + +async function getSuggestions(keyword) { + const { data } = await axios.get('https://anikototvapi.vercel.app/api/suggestions', { + params: { keyword } + }); + + return data.results; +} + +getSuggestions('one piece').then(suggestions => { + suggestions.forEach(a => console.log(`${a.title} (${a.slug})`)); +}); ``` -### Get Stream URL Only +### Schedule -```bash -curl -s "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9..." | jq -r '.results.url' +```javascript +const axios = require('axios'); + +async function getSchedule() { + const { data } = await axios.get('https://anikototvapi.vercel.app/api/schedule'); + + console.log('Scheduled anime:', data.results.length); + return data.results; +} + +getSchedule(); ``` diff --git a/docs/index.md b/docs/index.md index 60817dc..f96dc44 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,19 +11,53 @@ AniKotoAPI is a free, open-source REST API that provides anime data scraped from ## Quick Start ```bash -# Get homepage data +# Get homepage data (spotlight, trending, top-airing, genres) 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" +curl "https://anikototvapi.vercel.app/api/info?id=road-of-naruto-ggjw8" +``` + +**Live Response — Homepage:** + +```json +{ + "success": true, + "results": { + "spotlights": [ + { + "slug": "wistoria-wand-and-sword-season-2-dua04", + "poster": "https://cdn.anipixcdn.co/background/101f58336250ee0d_1779363645.webp", + "title": "Wistoria: Wand and Sword Season 2", + "japaneseTitle": "Tsue to Tsurugi no Wistoria Season 2", + "rating": "PG-13", + "quality": "HD" + } + ], + "trending": [ + { + "slug": "witch-hat-atelier-ikmut/ep-11", + "poster": "https://cdn.anipixcdn.co/thumbnail/0412057393e8a45b3ba8b16874b6034d.jpg", + "title": "Witch Hat Atelier", + "japaneseTitle": "Tongari Boushi no Atelier", + "sub": 11, + "dub": 11, + "total": 13, + "type": "TV" + } + ], + "topAiring": [...], + "genres": ["Action", "Adventure", "Cars", "Comedy", ...] + } +} ``` ## Features -- **24+ Endpoints** — Home, search, info, episodes, streaming, schedule, and more +- **27 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 @@ -31,10 +65,10 @@ curl "https://anikototvapi.vercel.app/api/info?id=naruto-shippuden" ## 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 +- [API Endpoints Reference](endpoints.md) — Complete endpoint documentation with real responses +- [Streaming Flow Guide](streaming.md) — How to get stream URLs step by step +- [Code Examples](examples.md) — cURL, JavaScript, Python (all tested and working) +- [Architecture](architecture.md) — Project structure and design decisions ## Response Format diff --git a/docs/streaming.md b/docs/streaming.md index 9a6bcbd..38ee9b6 100644 --- a/docs/streaming.md +++ b/docs/streaming.md @@ -1,23 +1,25 @@ # Streaming Flow Guide -> How to get streaming URLs from AniKotoAPI. +This guide explains how to get streaming URLs from AniKotoAPI in 3 steps. ## Overview -The streaming flow involves 3 steps: +``` +Step 1: Get Episodes → /api/episodes/:slug +Step 2: Get Servers → /api/servers?ids={server_ids} +Step 3: Get Stream URL → /api/stream?id={link_id} +``` -``` -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. +Each anime has multiple episodes. Fetch the episode list with the anime slug. + +**Request:** ```bash -curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden" +curl "https://anikototvapi.vercel.app/api/episodes/road-of-naruto-ggjw8" ``` **Response:** @@ -26,33 +28,37 @@ curl "https://anikototvapi.vercel.app/api/episodes/naruto-shippuden" { "success": true, "results": { - "animeId": 12345, - "slug": "naruto-shippuden", - "totalEpisodes": 500, + "animeId": "7174", + "totalEpisodes": 1, "episodes": [ { "id": "110289", "episode_no": 1, - "server_ids": "SlNVT25JaFlCMnZOeXZ2aG5t...", + "slug": "1", + "title": "", + "active": true, + "href": "#", + "server_ids": "SlNVT25JaFlCMnZOeXZ2aG5takIxL2EybGl4TzJoNE1pN3JXdFNlODVocWtTckt1SFR0YUxrNzNhanQ2MEJoVG9UUEZNeWJOMm1uUThpYjNxejhhUEZWMitnNFFtTUNMYjBTc1FJZjZNNFZPNm5LMlVuTnpOU25ScUI1dHVGczM0UzluZ2xITG5qbExabnBDdGphY0VRPT0", "timestamp": "1729249503", - "mal_id": "1735" + "mal_id": "53236" } ] } } ``` -**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 +> **Key field:** `server_ids` — Pass this to the next step. + +--- ## Step 2: Get Servers -Use the `server_ids` from step 1 to get available streaming servers. +Each episode has multiple servers. Use the `server_ids` from Step 1. + +**Request:** ```bash -curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25JaFlCMnZOeXZ2aG5t..." +curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25JaFlCMnZOeXZ2aG5takIxL2EybGl4TzJoNE1pN3JXdFNlODVocWtTckt1SFR0YUxrNzNhanQ2MEJoVG9UUEZNeWJOMm1uUThpYjNxejhhUEZWMitnNFFtTUNMYjBTc1FJZjZNNFZPNm5LMlVuTnpOU25ScUI1dHVGczM0UzluZ2xITG5qbExabnBDdGphY0VRPT0" ``` **Response:** @@ -64,42 +70,35 @@ curl "https://anikototvapi.vercel.app/api/servers?ids=SlNVT25JaFlCMnZOeXZ2aG5t.. { "type": "sub", "ep_id": "110289", - "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...", - "cmid": "animixplay-xxxxx", - "sv_id": "323", + "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ", + "cmid": "animixplay-fqs", + "sv_id": "1", "name": "HD-1" }, { "type": "sub", "ep_id": "110289", - "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...", - "cmid": "animixplay-xxxxx", - "sv_id": "e54", + "link_id": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOEZ4cFNpMDdQbnV1S3dNdklpRkhWbzRsVmgxSGx4YWx3LytPcnZXU0RCVHc9PQ", + "cmid": "animixplay-fqs", + "sv_id": "2", "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.) +> **Key field:** `link_id` — Pick a server and pass its `link_id` to the next step. + +--- ## Step 3: Get Stream URL -Use the `link_id` from step 2 to get the actual streaming URL. +Get the actual streaming URL using the `link_id` from Step 2. + +**Request:** ```bash -curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZr..." +curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ" ``` **Response:** @@ -108,7 +107,7 @@ curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZr { "success": true, "results": { - "linkId": "MTF1dkFtaW9BRTZPbzJJRElFZUZr...", + "linkId": "MTF1dkFtaW9BRTZPbzJJRElFZUZrOWdjeldjOERLaWNMMXFNbVB3WUJqOHZGS2FSWVgvbVJraVpIV1dQRjRoN01hOFUvYmxsWXFYNGtiR0h5OWdGQWc9PQ", "url": "https://megaplay.buzz/stream/s-5/94736/sub", "skipData": { "intro": [0, 0], @@ -118,96 +117,137 @@ curl "https://anikototvapi.vercel.app/api/stream?id=MTF1dkFtaW9BRTZPbzJJRElFZUZr } ``` -**Key fields:** -- `url` — Direct streaming URL (m3u8 or mp4) -- `skipData` — Intro/outro timestamps for skipping +> **Done!** Use `results.url` in your video player. -## Complete Example (JavaScript) +--- + +## JavaScript Example ```javascript -const BASE = "https://anikototvapi.vercel.app/api"; - -async function getStreamUrl(animeSlug, episodeNumber) { +async function getStreamUrl(animeSlug) { // 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 - ); + const episodesRes = await fetch(`https://anikototvapi.vercel.app/api/episodes/${animeSlug}`); + const episodesData = await episodesRes.json(); + const episodes = episodesData.results.episodes; - if (!episode) throw new Error("Episode not found"); + if (!episodes || episodes.length === 0) { + throw new Error('No episodes found'); + } + + // Use first episode's server_ids + const serverIds = episodes[0].server_ids; // 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]; + const serversRes = await fetch(`https://anikototvapi.vercel.app/api/servers?ids=${serverIds}`); + const serversData = await serversRes.json(); + const servers = serversData.results; - if (!server) throw new Error("No servers available"); + if (!servers || servers.length === 0) { + throw new Error('No servers found'); + } + + // Pick first server (HD-1) + const linkId = servers[0].link_id; // Step 3: Get stream URL - const streamRes = await fetch(`${BASE}/stream?id=${server.link_id}`); + const streamRes = await fetch(`https://anikototvapi.vercel.app/api/stream?id=${linkId}`); const streamData = await streamRes.json(); - return streamData.results; + return streamData.results.url; // "https://megaplay.buzz/stream/s-5/94736/sub" } // Usage -getStreamUrl("naruto-shippuden", 1) - .then(stream => { - console.log("Stream URL:", stream.url); - console.log("Skip intro at:", stream.skipData.intro[0]); - }); +getStreamUrl('road-of-naruto-ggjw8') + .then(url => console.log('Stream URL:', url)) + .catch(err => console.error('Error:', err)); ``` -## Complete Example (Python) +--- + +## Python Example ```python import requests -BASE = "https://anikototvapi.vercel.app/api" - -def get_stream_url(anime_slug, episode_number): +def get_stream_url(anime_slug): + base = "https://anikototvapi.vercel.app/api" + # 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 - ) + episodes_res = requests.get(f"{base}/episodes/{anime_slug}") + episodes_data = episodes_res.json() + episodes = episodes_data['results']['episodes'] + + if not episodes: + raise Exception("No episodes found") + + server_ids = episodes[0]['server_ids'] # 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] - ) + servers_res = requests.get(f"{base}/servers", params={"ids": server_ids}) + servers_data = servers_res.json() + servers = servers_data['results'] + + if not servers: + raise Exception("No servers found") + + link_id = servers[0]['link_id'] # Step 3: Get stream URL - stream_res = requests.get(f"{BASE}/stream", params={"id": server["link_id"]}) + stream_res = requests.get(f"{base}/stream", params={"id": link_id}) stream_data = stream_res.json() - return stream_data["results"] + return stream_data['results']['url'] # Usage -stream = get_stream_url("naruto-shippuden", 1) -print(f"Stream URL: {stream['url']}") -print(f"Skip intro at: {stream['skipData']['intro'][0]}") +url = get_stream_url('road-of-naruto-ggjw8') +print(f"Stream URL: {url}") ``` -## Alternative: Mapper Servers +--- -For additional streaming sources, use the mapper API with `malId`, `slug`, and `timestamp` from the episodes response. +## Player Integration -```bash -curl "https://anikototvapi.vercel.app/api/mapper-servers?malId=1735&slug=naruto-shippuden×tamp=1729249503" +### HLS.js (HLS Streams) + +```html + + + + ``` -This returns alternative providers like VidStreaming, Gogoanime, etc. +### Plyr (MP4 Streams) -## Notes +```html + + + -- 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 + +``` + +--- + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| "No episodes found" | Check the anime slug is correct (use `/api/search` first) | +| "No servers found" | The `server_ids` may be invalid, try another episode | +| Stream URL 403 | Some servers require specific referrer headers | +| CORS error | Use a proxy or access from server-side |