| name | bilibili-hub |
| description | A skill for reading and writing Bilibili data using Python + UV, powered by bilibili-api-python + aiohttp. Cookies are auto-acquired via browser_use get_cookies for authentication โ no manual copying needed. Supports video details / subtitles / AI summaries / comments, user profiles, search, trending / rankings, following feed, favorites, watch later, watch history, interactions (like / coin / triple), dynamic posting and deletion, etc. Trigger when user mentions "Bilibili", "bilibili", "Bilibili video", "Bilibili trending", "bilibili-hub", "get Bilibili data", "Bilibili subtitles", "Bilibili comments", "Bilibili favorites", "Bilibili dynamics", or any scenario requiring programmatic access to Bilibili content.
|
bilibili-hub
Forked from: jackwener/bilibili-cli (Apache-2.0)
This skill simplifies and adapts the original repo as follows:
- Removed
browser-cookie3 / click / rich / PyYAML / qrcode dependencies
- Cookie auth changed to accept
dict directly or read from env vars โ no browser auto-extraction
- Removed CLI layer (commands/), QR login, formatter, etc.
- Retained all API methods, unified as sync interface (
asyncio.run)
- Core dependency:
bilibili-api-python (reverse-engineered Bilibili API SDK)
- In Minis environment, cookies auto-acquired via
browser_use get_cookies
File Structure
/var/minis/skills/bilibili-hub/
โโโ SKILL.md
โโโ pyproject.toml # bilibili-api-python + aiohttp
โโโ scripts/
โโโ __init__.py
โโโ exceptions.py # 6 structured exceptions
โโโ payloads.py # Data normalization (normalize_* functions)
โโโ client.py # BiliClient core class (all API methods)
Authentication
Bilibili Web API uses three key cookies:
| Cookie | Description |
|---|
SESSDATA | User session (required, read operations) |
bili_jct | CSRF Token (required for write operations: like/coin/post dynamic, etc.) |
DedeUserID | User ID (recommended) |
buvid3 | Device ID (recommended, reduces anti-spam risk) |
Method 1: browser_use Auto-Acquire (Minis Preferred)
browser_use navigate to https://www.bilibili.com, confirm logged in
browser_use get_cookies to get cookies (raw values not exposed in conversation)
- Load the offload env file:
. /var/minis/offloads/env_cookies_www_bilibili_com_xxx.sh
export BILI_SESSDATA="$COOKIE_SESSDATA"
export BILI_JCT="$COOKIE_BILI_JCT"
export BILI_USERID="$COOKIE_DEDEUSERID"
export BILI_BUVID3="$COOKIE_BUVID3"
Note: get_cookies only works for the current page domain. Navigate to https://www.bilibili.com first before calling it.
Method 2: Manual from Browser DevTools
- Log into Bilibili, open DevTools โ Application โ Cookies โ
https://www.bilibili.com
- Find
SESSDATA, bili_jct, DedeUserID values
- Store in Minis env vars:
BILI_SESSDATA / BILI_JCT / BILI_USERID
Cookie Passing (Three Ways)
client = BiliClient.from_env()
client = BiliClient({
"SESSDATA": os.environ["BILI_SESSDATA"],
"bili_jct": os.environ["BILI_JCT"],
"DedeUserID": os.environ["BILI_USERID"],
})
client = BiliClient({"SESSDATA": os.environ["BILI_SESSDATA"]})
Quick Start
Environment Setup
cd /var/minis/skills/bilibili-hub
uv sync
Using as Python Library
import os, json, sys
sys.path.insert(0, "/var/minis/skills/bilibili-hub")
from scripts.client import BiliClient
client = BiliClient.from_env()
me = client.whoami()
print("User:", me.get("name"), "UID:", me.get("mid"))
videos = client.search_videos("Python tutorial", count=5)
for v in videos:
print(f" {v['bvid']} {v['title']} ({v['duration']})")
detail = client.get_video("BV1xx411c7mD", subtitle=True)
print(detail["video"]["title"])
print(detail["subtitle"]["text"][:200])
hot = client.get_hot(count=10)
for v in hot:
print(f" {v['bvid']} {v['title']} ๐{v['stats']['view']}")
API Reference
Account
| Method | Description |
|---|
whoami() | Get current logged-in user info |
Video
| Method | Description |
|---|
get_video(bvid, *, subtitle, subtitle_timeline, ai_summary, comments, related) | Get video details (optional subtitles/AI summary/comments/related) |
bvid accepts BV ID or full URL, auto-extracted.
User
| Method | Description |
|---|
get_user(uid) | Get user profile info + following/follower count |
get_user_videos(uid, count=20) | Get user's published videos |
Search
| Method | Description |
|---|
search_videos(keyword, page=1, count=20) | Search videos |
search_users(keyword, page=1) | Search users |
Discovery
| Method | Description |
|---|
get_hot(page=1, count=20) | Site-wide trending videos |
get_rank(day=3, count=50) | Site-wide ranking (day: 1/3/7) |
get_feed(offset=0) | Following feed (login required) |
get_my_dynamics(offset=0) | My posted dynamics (login required) |
post_dynamic(text) | Post text dynamic (login + bili_jct required) |
delete_dynamic(dynamic_id) | Delete dynamic (login + bili_jct required) |
Favorites / History
| Method | Description |
|---|
get_favorites() | Get favorite folder list (login required) |
get_favorites(folder_id) | Get videos in a favorite folder |
get_following(page=1) | Get following list (login required) |
get_watch_later() | Watch later list (login required) |
get_history() | Watch history (login required) |
Download
| Method | Description |
|---|
download_video(bvid, output_dir, filename=None) | Download full video (mp4), auto-handles DASH merging |
download_audio(bvid, output_dir, filename=None) | Download audio stream only (m4a), suitable for ASR |
Download flow:
- DASH stream (common): download video stream + audio stream separately โ ffmpeg copy merge โ on failure, keep silent video
- FLV/MP4 stream (rare): download directly, no merge needed
- Unauthenticated: up to 480P; logged-in: up to 1080P (premium members get higher)
| Method | Description |
|---|
like(bvid) / like(bvid, undo=True) | Like / Unlike (bili_jct required) |
coin(bvid, num=1) | Coin 1 or 2 (bili_jct required) |
triple(bvid) | Triple (like + coin + favorite) (bili_jct required) |
unfollow(uid) | Unfollow user (bili_jct required) |
Error Handling
from scripts.exceptions import (
AuthenticationError,
RateLimitError,
NotFoundError,
NetworkError,
InvalidBvidError,
BiliError,
)
try:
detail = client.get_video("BV1xx411c7mD")
except AuthenticationError:
print("Cookie expired, please re-acquire")
except RateLimitError:
print("Anti-spam triggered, retry later")
except NotFoundError:
print("Video not found")
except BiliError as e:
print(f"API error: {e}")
Notes
SESSDATA is the minimum requirement for read operations; write operations (like/coin/post dynamic) also need bili_jct
- Cookie validity is typically days to weeks; re-acquire via
browser_use get_cookies when expired
- Bilibili rate-limits high-frequency requests (HTTP 412); recommended interval >= 1 second
bilibili-api-python is a community-maintained reverse-engineering project; endpoints may break when Bilibili updates
- Write operations (coin/triple, etc.) are irreversible โ use with caution