Build an anime Telegram bot
A Telegram bot in Python with two commands: /search to find anime and /episodes to list a title's seasons. It uses the AnimeDoc API and runs on the Free plan.
What you need
- Python 3.10 or newer.
- A bot token: message @BotFather on Telegram and send
/newbot. - An AnimeDoc API key. Get one free.
pip install "python-telegram-bot>=21" httpxThe bot
import os
import httpx
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
API = "https://api.animedoc.cloud/api/v2"
HEADERS = {"X-API-Key": os.environ["ANIMEDOC_API_KEY"]}
client = httpx.AsyncClient(timeout=15, headers=HEADERS)
async def call(method: str, path: str, **kwargs):
res = await client.request(method, API + path, **kwargs)
if res.status_code == 429:
raise RuntimeError("Too many requests right now, try again in a minute.")
res.raise_for_status()
return res.json()["data"]
async def search(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = " ".join(context.args)
if not query:
await update.message.reply_text("Usage: /search <anime title>")
return
try:
data = await call("POST", "/anime/search/", json={"keyword": query, "page": 1, "perPage": 5})
except RuntimeError as e:
await update.message.reply_text(str(e))
return
items = data.get("items") or []
if not items:
await update.message.reply_text(f"Nothing found for {query!r}.")
return
lines = []
for item in items:
year = (item.get("releaseDate") or "")[:4]
rating = item.get("imdbRatingValue") or "–"
lines.append(f"• {item['title']} ({year}) ⭐ {rating}\n /episodes {item['detailPath']}")
await update.message.reply_text("\n".join(lines))
async def episodes(update: Update, context: ContextTypes.DEFAULT_TYPE):
if not context.args:
await update.message.reply_text("Usage: /episodes <detailPath from /search>")
return
data = await call("GET", "/anime/detail/", params={"detailPath": context.args[0]})
subject = data["subject"]
seasons = (data.get("resource") or {}).get("seasons") or []
if not seasons or seasons[0]["maxEp"] == 0:
summary = "Movie"
else:
summary = ", ".join(f"Season {s['se']}: {s['maxEp']} episodes" for s in seasons)
await update.message.reply_photo(
photo=(subject.get("cover") or {}).get("url"),
caption=f"{subject['title']}\n{summary}\n\n{(subject.get('description') or '')[:600]}",
)
def main():
app = Application.builder().token(os.environ["TELEGRAM_BOT_TOKEN"]).build()
app.add_handler(CommandHandler("search", search))
app.add_handler(CommandHandler("episodes", episodes))
app.run_polling()
if __name__ == "__main__":
main()Run it
export TELEGRAM_BOT_TOKEN=123456:ABC...
export ANIMEDOC_API_KEY=ad_live_...
python bot.pyIn Telegram, send your bot /search frieren, then tap one of the /episodes commands it replies with.
Limits and next steps
- Each command uses one request. The Free plan's 20 requests a day suits a personal bot; a group bot will want Starter (3,000 a day).
- Cache results in a dict keyed by query for a few minutes to save requests.
- To send episodes, add a command that calls Media Sources and links to your own player.