bilibili-hub · git:20260801.3cb01ce · 2026-08-01 · sha256 ff17d31dbfbaf4e2
bilibili-hub git:20260801.3cb01ceA
Immutable. This exact content is served forever at /api/v1/blob/ff17d31dbfbaf4e2.
---
name: bilibili-hub
description: >
A skill for reading and writing Bilibili data with Python + UV, using bilibili-api-python + aiohttp.
It automatically obtains cookies through `browser_use get_cookies` for authentication, so no manual copying is required.
Supports video details, subtitles, AI summaries, comments, user profiles, search, popular videos/rankings, following dynamics feed,
favorites, Watch Later, viewing history, interactions (likes, coins, triple action), publishing and deleting dynamics, and more.
When a user mentions "Bilibili," "bilibili," "Bilibili videos," "Bilibili popular," "bilibili-hub,"
"get Bilibili data," "Bilibili subtitles," "Bilibili comments," "Bilibili favorites," "Bilibili dynamics,"
or any scenario that requires programmatically reading or writing Bilibili content, this skill must be triggered.
---
# bilibili-hub
> **Modified from**: [jackwener/bilibili-cli](https://github.com/jackwener/bilibili-cli) (Apache-2.0)
>
> This skill simplifies and modifies the original repository as follows:
> - Removed the `browser-cookie3` / `click` / `rich` / `PyYAML` / `qrcode` dependencies
> - Changed cookie authentication to accept a `dict` directly or read from environment variables, without automatic browser extraction
> - Removed the CLI layer (`commands/`), QR login, formatters, and related components
> - Kept all API methods and wrapped them uniformly as synchronous interfaces (`asyncio.run`)
> - Core dependency: `bilibili-api-python`, a third-party SDK that reverse engineers the Bilibili API
> - In the Minis environment, cookies are obtained automatically through `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 exception types
├── payloads.py # Data structure normalization (normalize_* functions)
└── client.py # BiliClient core class (all API methods)
```
---
## Authentication Methods
The Bilibili Web API uses three key cookies:
| Cookie | Description |
|--------|------|
| `SESSDATA` | User session (required for read operations) |
| `bili_jct` | CSRF token (required for write operations: likes, coins, posting dynamics, etc.) |
| `DedeUserID` | User ID (recommended) |
| `buvid3` | Device ID (recommended; reduces the likelihood of triggering risk control) |
### Method 1: Automatically retrieve via `browser_use` (preferred in Minis environments)
1. Use `browser_use navigate` to open `https://www.bilibili.com` and confirm that you are logged in.
2. Use `browser_use get_cookies` to retrieve cookies (raw values do not appear in the conversation).
3. Load the offload env file:
```bash
. /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 applies to the current page's domain. Navigate to `https://www.bilibili.com` before calling it.
### Method 2: Manually retrieve from browser DevTools
1. Log in to Bilibili, then open DevTools -> Application -> Cookies -> `https://www.bilibili.com`.
2. Find the values of `SESSDATA`, `bili_jct`, and `DedeUserID`.
3. Store them in the Minis environment variables: `BILI_SESSDATA` / `BILI_JCT` / `BILI_USERID`.
### Ways to pass cookies (three methods)
```python
# Method 1: From environment variables (recommended)
client = BiliClient.from_env()
# Method 2: Pass a dict directly
client = BiliClient({
"SESSDATA": os.environ["BILI_SESSDATA"],
"bili_jct": os.environ["BILI_JCT"],
"DedeUserID": os.environ["BILI_USERID"],
})
# Method 3: Read-only operations (no write permissions required)
client = BiliClient({"SESSDATA": os.environ["BILI_SESSDATA"]})
```
---
## Quick Start
### Environment setup
```bash
cd /var/minis/skills/bilibili-hub
uv sync
```
### Calling as a Python library
```python
import os, json, sys
sys.path.insert(0, "/var/minis/skills/bilibili-hub")
from scripts.client import BiliClient
client = BiliClient.from_env()
# Current user information
me = client.whoami()
print("User:", me.get("name"), "UID:", me.get("mid"))
# Search videos
videos = client.search_videos("Python Tutorial", count=5)
for v in videos:
print(f" {v['bvid']} {v['title']} ({v['duration']})")
# Get video details (including subtitles)
detail = client.get_video("BV1xx411c7mD", subtitle=True)
print(detail["video"]["title"])
print(detail["subtitle"]["text"][:200])
# Popular videos
hot = client.get_hot(count=10)
for v in hot:
print(f" {v['bvid']} {v['title']} 👁{v['stats']['view']}")
```
---
## API Method Quick Reference
### Account
| Method | Description |
|------|------|
| `whoami()` | Get information about the currently logged-in user |
### Video
| Method | Description |
|------|------|
| `get_video(bvid, *, subtitle, subtitle_timeline, ai_summary, comments, related)` | Get video details (optional subtitles/AI summary/comments/related videos) |
`bvid` supports a BV number or full URL and is extracted automatically.
### Users
| Method | Description |
|------|------|
| `get_user(uid)` | Get user profile information + following/follower counts |
| `get_user_videos(uid, count=20)` | Get videos posted by a user |
### Search
| Method | Description |
|------|------|
| `search_videos(keyword, page=1, count=20)` | Search videos |
| `search_users(keyword, page=1)` | Search users |
### Discover
| Method | Description |
|------|------|
| `get_hot(page=1, count=20)` | Site-wide popular videos |
| `get_rank(day=3, count=50)` | Site-wide rankings (`day`: 1/3/7) |
| `get_feed(offset=0)` | Following dynamics feed (login required) |
| `get_my_dynamics(offset=0)` | Dynamics I published (login required) |
| `post_dynamic(text)` | Post a text dynamic (login + `bili_jct` required) |
| `delete_dynamic(dynamic_id)` | Delete a dynamic (login + `bili_jct` required) |
### Favorites / History
| Method | Description |
|------|------|
| `get_favorites()` | Get the favorites folder list (login required) |
| `get_favorites(folder_id)` | Get videos in a favorites folder |
| `get_following(page=1)` | Get the following list (login required) |
| `get_watch_later()` | Get the Watch Later list (login required) |
| `get_history()` | Get viewing history (login required) |
### Download
| Method | Description |
|------|------|
| `download_video(bvid, output_dir, filename=None)` | Download the full video (`mp4`), automatically handling DASH merging |
| `download_audio(bvid, output_dir, filename=None)` | Download only the audio stream (`m4a`), suitable for ASR transcription |
**Download process**:
- DASH streams (common): download the video stream and audio stream separately -> merge with `ffmpeg copy` -> if merging fails, keep the silent video
- FLV/MP4 streams (rare): download directly, no merging required
- Without logging in, downloads are limited to 480P; after logging in, 1080P is available (premium members can download higher quality)
| Method | Description |
|------|------|
| `like(bvid)` / `like(bvid, undo=True)` | Like / unlike (requires `bili_jct`) |
| `coin(bvid, num=1)` | Give 1 or 2 coins (requires `bili_jct`) |
| `triple(bvid)` | Perform the one-click triple action (requires `bili_jct`) |
| `unfollow(uid)` | Unfollow a user (requires `bili_jct`) |
---
## Error Handling
```python
from scripts.exceptions import (
AuthenticationError, # Cookie missing or expired
RateLimitError, # Triggered risk control (412)
NotFoundError, # Video/user does not exist
NetworkError, # Network/timeout error
InvalidBvidError, # Invalid BV number format
BiliError, # Other API error (base class)
)
try:
detail = client.get_video("BV1xx411c7mD")
except AuthenticationError:
print("Cookie has expired. Please retrieve it again.")
except RateLimitError:
print("Risk control triggered. Try again later.")
except NotFoundError:
print("Video does not exist.")
except BiliError as e:
print(f"API error: {e}")
```
---
## Important Notes
- `SESSDATA` is the minimum requirement for read operations. Write operations (likes, coins, posting dynamics) also require `bili_jct`.
- Cookies are usually valid for several days to several weeks. After they expire, retrieve them again through `browser_use get_cookies`.
- Bilibili applies risk control to high-frequency requests (HTTP 412). An operation interval of at least 1 second is recommended.
- `bilibili-api-python` is a community-maintained reverse-engineering project, and its interfaces may break when Bilibili updates.
- Write operations (coins, triple action, etc.) cannot be reversed. Use them with caution.