bilibili-hub
Modified from: 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)
- Use
browser_use navigate to open https://www.bilibili.com and confirm that you are logged in.
- Use
browser_use get_cookies to retrieve cookies (raw values do not appear in the 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 applies to the current page's domain. Navigate to https://www.bilibili.com before calling it.
Method 2: Manually retrieve from browser DevTools
- Log in to Bilibili, then open DevTools -> Application -> Cookies ->
https://www.bilibili.com.
- Find the values of
SESSDATA, bili_jct, and DedeUserID.
- Store them in the Minis environment variables:
BILI_SESSDATA / BILI_JCT / BILI_USERID.
Ways to pass cookies (three methods)
# 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
cd /var/minis/skills/bilibili-hub
uv sync
Calling as a Python library
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
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.
1---2name: bilibili-hub3description: 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.4---56# bilibili-hub78> **Modified from**: [jackwener/bilibili-cli](https://github.com/jackwener/bilibili-cli) (Apache-2.0)9>10> This skill simplifies and modifies the original repository as follows:11> - Removed the `browser-cookie3` / `click` / `rich` / `PyYAML` / `qrcode` dependencies12> - Changed cookie authentication to accept a `dict` directly or read from environment variables, without automatic browser extraction13> - Removed the CLI layer (`commands/`), QR login, formatters, and related components14> - Kept all API methods and wrapped them uniformly as synchronous interfaces (`asyncio.run`)15> - Core dependency: `bilibili-api-python`, a third-party SDK that reverse engineers the Bilibili API16> - In the Minis environment, cookies are obtained automatically through `browser_use get_cookies`1718---1920## File Structure2122```23/var/minis/skills/bilibili-hub/24├── SKILL.md25├── pyproject.toml # bilibili-api-python + aiohttp26└── scripts/27 ├── __init__.py28 ├── exceptions.py # 6 structured exception types29 ├── payloads.py # Data structure normalization (normalize_* functions)30 └── client.py # BiliClient core class (all API methods)31```3233---3435## Authentication Methods3637The Bilibili Web API uses three key cookies:3839| Cookie | Description |40|--------|------|41| `SESSDATA` | User session (required for read operations) |42| `bili_jct` | CSRF token (required for write operations: likes, coins, posting dynamics, etc.) |43| `DedeUserID` | User ID (recommended) |44| `buvid3` | Device ID (recommended; reduces the likelihood of triggering risk control) |4546### Method 1: Automatically retrieve via `browser_use` (preferred in Minis environments)47481. Use `browser_use navigate` to open `https://www.bilibili.com` and confirm that you are logged in.492. Use `browser_use get_cookies` to retrieve cookies (raw values do not appear in the conversation).503. Load the offload env file:5152```bash53. /var/minis/offloads/env_cookies_www_bilibili_com_xxx.sh54export BILI_SESSDATA="$COOKIE_SESSDATA"55export BILI_JCT="$COOKIE_BILI_JCT"56export BILI_USERID="$COOKIE_DEDEUSERID"57export BILI_BUVID3="$COOKIE_BUVID3"58```5960> **Note**: `get_cookies` only applies to the current page's domain. Navigate to `https://www.bilibili.com` before calling it.6162### Method 2: Manually retrieve from browser DevTools63641. Log in to Bilibili, then open DevTools -> Application -> Cookies -> `https://www.bilibili.com`.652. Find the values of `SESSDATA`, `bili_jct`, and `DedeUserID`.663. Store them in the Minis environment variables: `BILI_SESSDATA` / `BILI_JCT` / `BILI_USERID`.6768### Ways to pass cookies (three methods)6970```python71# Method 1: From environment variables (recommended)72client = BiliClient.from_env()7374# Method 2: Pass a dict directly75client = BiliClient({76 "SESSDATA": os.environ["BILI_SESSDATA"],77 "bili_jct": os.environ["BILI_JCT"],78 "DedeUserID": os.environ["BILI_USERID"],79})8081# Method 3: Read-only operations (no write permissions required)82client = BiliClient({"SESSDATA": os.environ["BILI_SESSDATA"]})83```8485---8687## Quick Start8889### Environment setup9091```bash92cd /var/minis/skills/bilibili-hub93uv sync94```9596### Calling as a Python library9798```python99import os, json, sys100sys.path.insert(0, "/var/minis/skills/bilibili-hub")101from scripts.client import BiliClient102103client = BiliClient.from_env()104105# Current user information106me = client.whoami()107print("User:", me.get("name"), "UID:", me.get("mid"))108109# Search videos110videos = client.search_videos("Python Tutorial", count=5)111for v in videos:112 print(f" {v['bvid']} {v['title']} ({v['duration']})")113114# Get video details (including subtitles)115detail = client.get_video("BV1xx411c7mD", subtitle=True)116print(detail["video"]["title"])117print(detail["subtitle"]["text"][:200])118119# Popular videos120hot = client.get_hot(count=10)121for v in hot:122 print(f" {v['bvid']} {v['title']} 👁{v['stats']['view']}")123```124125---126127## API Method Quick Reference128129### Account130131| Method | Description |132|------|------|133| `whoami()` | Get information about the currently logged-in user |134135### Video136137| Method | Description |138|------|------|139| `get_video(bvid, *, subtitle, subtitle_timeline, ai_summary, comments, related)` | Get video details (optional subtitles/AI summary/comments/related videos) |140141`bvid` supports a BV number or full URL and is extracted automatically.142143### Users144145| Method | Description |146|------|------|147| `get_user(uid)` | Get user profile information + following/follower counts |148| `get_user_videos(uid, count=20)` | Get videos posted by a user |149150### Search151152| Method | Description |153|------|------|154| `search_videos(keyword, page=1, count=20)` | Search videos |155| `search_users(keyword, page=1)` | Search users |156157### Discover158159| Method | Description |160|------|------|161| `get_hot(page=1, count=20)` | Site-wide popular videos |162| `get_rank(day=3, count=50)` | Site-wide rankings (`day`: 1/3/7) |163| `get_feed(offset=0)` | Following dynamics feed (login required) |164| `get_my_dynamics(offset=0)` | Dynamics I published (login required) |165| `post_dynamic(text)` | Post a text dynamic (login + `bili_jct` required) |166| `delete_dynamic(dynamic_id)` | Delete a dynamic (login + `bili_jct` required) |167168### Favorites / History169170| Method | Description |171|------|------|172| `get_favorites()` | Get the favorites folder list (login required) |173| `get_favorites(folder_id)` | Get videos in a favorites folder |174| `get_following(page=1)` | Get the following list (login required) |175| `get_watch_later()` | Get the Watch Later list (login required) |176| `get_history()` | Get viewing history (login required) |177178### Download179180| Method | Description |181|------|------|182| `download_video(bvid, output_dir, filename=None)` | Download the full video (`mp4`), automatically handling DASH merging |183| `download_audio(bvid, output_dir, filename=None)` | Download only the audio stream (`m4a`), suitable for ASR transcription |184185**Download process**:186- DASH streams (common): download the video stream and audio stream separately -> merge with `ffmpeg copy` -> if merging fails, keep the silent video187- FLV/MP4 streams (rare): download directly, no merging required188- Without logging in, downloads are limited to 480P; after logging in, 1080P is available (premium members can download higher quality)189190| Method | Description |191|------|------|192| `like(bvid)` / `like(bvid, undo=True)` | Like / unlike (requires `bili_jct`) |193| `coin(bvid, num=1)` | Give 1 or 2 coins (requires `bili_jct`) |194| `triple(bvid)` | Perform the one-click triple action (requires `bili_jct`) |195| `unfollow(uid)` | Unfollow a user (requires `bili_jct`) |196197---198199## Error Handling200201```python202from scripts.exceptions import (203 AuthenticationError, # Cookie missing or expired204 RateLimitError, # Triggered risk control (412)205 NotFoundError, # Video/user does not exist206 NetworkError, # Network/timeout error207 InvalidBvidError, # Invalid BV number format208 BiliError, # Other API error (base class)209)210211try:212 detail = client.get_video("BV1xx411c7mD")213except AuthenticationError:214 print("Cookie has expired. Please retrieve it again.")215except RateLimitError:216 print("Risk control triggered. Try again later.")217except NotFoundError:218 print("Video does not exist.")219except BiliError as e:220 print(f"API error: {e}")221```222223---224225## Important Notes226227- `SESSDATA` is the minimum requirement for read operations. Write operations (likes, coins, posting dynamics) also require `bili_jct`.228- Cookies are usually valid for several days to several weeks. After they expire, retrieve them again through `browser_use get_cookies`.229- Bilibili applies risk control to high-frequency requests (HTTP 412). An operation interval of at least 1 second is recommended.230- `bilibili-api-python` is a community-maintained reverse-engineering project, and its interfaces may break when Bilibili updates.231- Write operations (coins, triple action, etc.) cannot be reversed. Use them with caution.