Skip to content

Sheets-Astrum-BOT/AnimeKai-API-Python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AnimeKai Scraper API

FastAPI wrapper around the AnimeKai scraping workflow. This project turns the original Aniyomi/Tachiyomi scraper in into a documented HTTP API with:

  • ReDoc at /redoc
  • Swagger UI at /docs
  • typed JSON responses
  • episode token extraction
  • AnimeKai search and detail scraping
  • stream resolution for playable HLS URLs

What This API Does

The service exposes the same high-level flow a client would use manually:

  1. search or browse anime
  2. fetch details for a selected title
  3. fetch episode tokens for that title
  4. resolve playable stream URLs for one episode token

The main public endpoints are:

Endpoint Purpose
GET / API metadata
GET /health health check
GET /filters supported search filter values
GET /catalog/popular trending/popular anime
GET /catalog/latest latest updated anime
GET /catalog/search keyword + filter search
GET /anime/details metadata for one anime
GET /anime/episodes episodes and episode tokens
GET /videos resolved stream URLs for one episode token

Interactive Docs

After starting the server:

  • ReDoc: http://127.0.0.1:8000/redoc
  • Swagger UI: http://127.0.0.1:8000/docs
  • OpenAPI JSON: http://127.0.0.1:8000/openapi.json

The README below is meant to be the hand-written reference. /docs remains the source of truth for exact schema and query parameters.

Quick Start

Option 1: uv

uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
uv run uvicorn app.main:app --reload

Without activating the virtualenv:

uv venv
uv pip install --python .venv/bin/python -e ".[dev]"
uv run --python .venv/bin/python uvicorn app.main:app --reload

Option 2: venv + pip

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/uvicorn app.main:app --reload

The app listens on http://127.0.0.1:8000 by default.

Environment Variables

Variable Default Meaning
ANIMEKAI_BASE_URL https://anikai.to default upstream AnimeKai domain
ANIMEKAI_INCLUDE_ADULT false include adult-tagged titles in browse/search
ANIMEKAI_TITLE_LANGUAGE en en or romaji title preference
ANIMEKAI_ENABLED_TYPES sub,dub,softsub which stream groups are resolved by default
ANIMEKAI_PREFERRED_QUALITY 1080 result sorting preference only
ANIMEKAI_PREFERRED_TYPE Subtitled result sorting preference only
ANIMEKAI_PREFERRED_SERVER Server 1 result sorting preference only
ANIMEKAI_USER_AGENT browser-like UA outbound request user-agent
ANIMEKAI_TIMEOUT_SECONDS 20 upstream request timeout

Response Conventions

  • anime_path is the relative AnimeKai watch path, for example /watch/naruto-9r5k
  • watch_path in /videos is the same type of relative path returned by /anime/episodes
  • episode_token comes from /anime/episodes
  • /videos returns stream candidates sorted by your preferred quality, type, and server
  • upstream failures are returned as HTTP 502
  • invalid filter values are returned as HTTP 422

Recommended Client Flow

1. Search for a title

curl "http://127.0.0.1:8000/catalog/search?query=naruto"

2. Pick one path from the search results

Example:

"/watch/naruto-9r5k"

3. Fetch details

curl "http://127.0.0.1:8000/anime/details?anime_path=/watch/naruto-9r5k"

4. Fetch episodes

curl "http://127.0.0.1:8000/anime/episodes?anime_path=/watch/naruto-9r5k"

5. Pick one episode token

Example:

"NcK_8PHzqEm40nVK0JqH"

6. Resolve stream URLs

curl "http://127.0.0.1:8000/videos?watch_path=/watch/naruto-9r5k&episode_token=NcK_8PHzqEm40nVK0JqH&enabled_types=sub"

Endpoint Reference

GET /

Returns basic API metadata.

Example response:

{
  "name": "AnimeKai Scraper API",
  "version": "0.1.0",
  "docs_url": "/docs",
  "redoc_url": "/redoc"
}

GET /health

Returns the current service health and configured upstream base URL.

Example response:

{
  "status": "ok",
  "upstream_base_url": "https://anikai.to"
}

GET /filters

Returns valid values for search filters. Use this when building a frontend or SDK instead of hardcoding ids.

Useful query behavior:

  • search accepts either ids or labels for many filter groups
  • sort=auto is converted internally:
    • to most_relevance when query is non-empty
    • to trending when query is empty

Partial example response:

{
  "sort": [
    "auto",
    "most_relevance",
    "updated_date",
    "release_date",
    "end_date",
    "trending"
  ],
  "genres": [
    { "id": "47", "label": "Action" },
    { "id": "1", "label": "Adventure" }
  ],
  "statuses": [
    { "id": "info", "label": "Not Aired Yet" },
    { "id": "releasing", "label": "Releasing" },
    { "id": "completed", "label": "Completed" }
  ]
}

GET /catalog/popular

Popular/trending catalog listing.

Query parameters:

Name Type Default Notes
page int 1 page number
base_url str configured default override AnimeKai domain
include_adult bool env default include adult titles
title_language `en romaji` env default

Example request:

curl "http://127.0.0.1:8000/catalog/popular?page=1"

GET /catalog/latest

Latest-updates listing.

Query parameters are the same as /catalog/popular.

Example request:

curl "http://127.0.0.1:8000/catalog/latest?page=1"

GET /catalog/search

Search AnimeKai by keyword and optional filters.

Key query parameters:

Name Type Notes
query str keyword search
page int page number
sort str see /filters
genres repeated str ids or labels
exclude_genres repeated str ids or labels
statuses repeated str ids or labels
types repeated str ids or labels
seasons repeated str ids or labels
languages repeated str ids or labels
countries repeated str ids or labels
ratings repeated str ids or labels
years repeated str exact years or buckets like 1990s
include_adult bool include adult results
title_language `en romaji`

Example request:

curl "http://127.0.0.1:8000/catalog/search?query=naruto&sort=auto"

Sample response:

{
  "page": 1,
  "has_next_page": false,
  "source_url": "https://anikai.to/browser",
  "applied_filters": {
    "sort": "auto",
    "genres": [],
    "exclude_genres": [],
    "statuses": [],
    "types": [],
    "seasons": [],
    "languages": [],
    "countries": [],
    "ratings": [],
    "years": []
  },
  "items": [
    {
      "title": "Naruto",
      "alt_title": "NARUTO",
      "path": "/watch/naruto-9r5k",
      "thumbnail_url": "https://static.anikai.to/e8/i/9/13/67664948cb6c6@300.jpg",
      "adult": false
    },
    {
      "title": "Naruto Shippuden",
      "alt_title": "NARUTO: Shippuuden",
      "path": "/watch/naruto-shippuden-mv9v",
      "thumbnail_url": "https://static.anikai.to/5a/i/9/8a/67664abaf05fa@300.jpg",
      "adult": false
    }
  ]
}

GET /anime/details

Returns metadata for one anime page.

Query parameters:

Name Type Required Notes
anime_path str yes relative AnimeKai watch path
base_url str no upstream override
title_language `en romaji` no

Example request:

curl "http://127.0.0.1:8000/anime/details?anime_path=/watch/naruto-9r5k"

Sample response:

{
  "path": "/watch/naruto-9r5k",
  "title": "Naruto",
  "alt_title": "NARUTO",
  "thumbnail_url": "http://static.1cdn.me/i/9/13/67664948cb6c6.jpg",
  "description": "Twelve years ago, a colossal demon fox terrorized the world...",
  "genres": [
    "Adventure",
    "Comedy",
    "Fantasy",
    "Shounen",
    "Action",
    "Supernatural",
    "Drama",
    "Martial Arts"
  ],
  "status": "Completed",
  "studios": ["Studio Pierrot"],
  "producers": ["Aniplex", "TV Tokyo"]
}

GET /anime/episodes

Returns episodes for an anime along with the token needed by /videos.

Query parameters:

Name Type Required
anime_path str yes
base_url str no

Example request:

curl "http://127.0.0.1:8000/anime/episodes?anime_path=/watch/naruto-9r5k"

Sample response:

[
  {
    "number": 220.0,
    "title": "Going on a Journey",
    "name": "Episode 220: Going on a Journey",
    "labels": ["Sub & Dub"],
    "token": "NcK_8PHzqEm40nVK0JqH",
    "watch_path": "/watch/naruto-9r5k"
  },
  {
    "number": 219.0,
    "title": "The Revived Ultimate Weapon",
    "name": "Episode 219: The Revived Ultimate Weapon",
    "labels": ["Sub & Dub", "Filler"],
    "token": "d8W6rqPx4wXj0W9K2ZSU",
    "watch_path": "/watch/naruto-9r5k"
  }
]

GET /videos

Resolves actual playable stream URLs for one episode token.

Query parameters:

Name Type Required Notes
watch_path str yes use the value returned from /anime/episodes
episode_token str yes use the episode token from /anime/episodes
base_url str no upstream override
enabled_types repeated `sub dub softsub`
preferred_quality str no affects sorting only
preferred_type_label str no affects sorting only
preferred_server str no affects sorting only

Example request:

curl "http://127.0.0.1:8000/videos?watch_path=/watch/naruto-9r5k&episode_token=NcK_8PHzqEm40nVK0JqH&enabled_types=sub&preferred_quality=1080&preferred_type_label=Subtitled&preferred_server=Server%201"

Sample response:

{
  "total": 6,
  "preferred_quality": "1080",
  "preferred_type_label": "Subtitled",
  "preferred_server": "Server 1",
  "items": [
    {
      "quality": "Subtitled | Server 1 | 1080p",
      "url": "https://rrr.tech20hub.site/.../1080.m3u8",
      "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Referer": "https://anikai.to"
      },
      "subtitles": [],
      "source_type": "sub",
      "source_type_label": "Subtitled",
      "server_name": "Server 1"
    },
    {
      "quality": "Subtitled | Server 2 | 1080p",
      "url": "https://rrr.megaup.cc/.../1080.m3u8",
      "headers": {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Referer": "https://anikai.to"
      },
      "subtitles": [],
      "source_type": "sub",
      "source_type_label": "Subtitled",
      "server_name": "Server 2"
    }
  ]
}

Errors

Typical error responses:

Upstream failure

HTTP 502

{
  "detail": "Upstream request failed with status 503."
}

or

{
  "detail": "Unable to extract video streams from the resolved servers. sub/Server 1: ..."
}

Invalid filter input

HTTP 422

{
  "detail": "Invalid genre value(s): bad-value. Use the ids or labels from /filters."
}

Notes About Example Output

  • The sample JSON above is intentionally trimmed to keep the README readable.
  • For exact current schema and live responses, prefer /docs and direct requests to the running API.
  • Values like stream URLs, thumbnails, available servers, and tokens come from live upstream scraping and can change at any time.