Bilibili Video Evidence
Collect evidence first. Write notes later.
Workflow
- Parse the BV id and optional
p= page index from the user URL.
- Fetch native subtitles before considering ASR or summaries.
- If the page exposes no usable subtitle track, or the user explicitly asks for a local/offline subtitle path, switch to the local ASR fallback in references/asr-fallback.md.
- Write native subtitle artifacts with
scripts/bilibili_subtitle_to_md.py, or write ASR fallback artifacts with scripts/bilibili_audio_asr_to_srt.py after the fallback decision is made.
- Capture direct frame artifacts with
scripts/capture_bilibili_screenshot.js when the user wants PNG evidence files.
- Inspect the repo for an existing screenshot endpoint before adding code.
- Run
scripts/smoke_bilibili_endpoint.js only when the task is specifically about validating a repo-local screenshot route.
- Report native subtitle access, ASR fallback status, and screenshot access separately.
Outputs
sectioned.md
subtitles.json
audio-16k.wav
asr.srt
asr.zh.srt
asr.json
frames/*.png
- optional
smoke-report.json
Run
Use:
python scripts/bilibili_subtitle_to_md.py \
--url "https://www.bilibili.com/video/BV1X7411F744?p=5" \
--output "sectioned.md" \
--json-output "subtitles.json"
If Bilibili exposes no usable subtitle track, run the local ASR fallback:
python scripts/bilibili_audio_asr_to_srt.py \
--url "https://www.bilibili.com/video/BV1X7411F744?p=5" \
--cookie-file "cookie.txt" \
--output-dir "outputs/P05" \
--model "small" \
--device "cpu" \
--compute-type "int8"
When a Chinese subtitle translation is requested after ASR, keep the .srt numbering and timestamps unchanged, translate only the subtitle text, and preserve technical keywords in English. Read references/asr-fallback.md for the exact fallback rules and prompt pattern.
Capture a frame directly:
node scripts/capture_bilibili_screenshot.js \
"https://www.bilibili.com/video/BV15DG7zxENa/" \
00:24 \
--output=frames/intro.png
Validate a repo-local screenshot endpoint:
node scripts/smoke_bilibili_endpoint.js <repo-root> <bilibili-url> --timestamps=00:13,10:25
Cookie Handling
- Prefer the full browser
Cookie header over SESSDATA alone.
- Accept either
--cookie or --cookie-file.
- If neither is passed, the subtitle script may fall back to
BILIBILI_COOKIE or BILIBILI_SESSION_TOKEN from the environment.
- Strip a leading
Cookie: prefix if the user pasted a raw header line.
- Try
x/player/v2 first and keep x/player/wbi/v2 as a fallback source.
- The local ASR fallback may still need browser cookie state to resolve or fetch the media stream.
- If login-gated subtitle access still fails, ask for a fresh full
Cookie header or Copy as cURL.
- Treat frame capture success and subtitle access as separate checks.
Subtitle Artifacts
The subtitle script writes Markdown with:
- video title
- source URL
- BV id and CID
- page index and page title
- subtitle language and subtitle URL
- subtitle count
- timeline sections grouped by fixed-length buckets
If --output is omitted, the default Markdown filename is the sanitized video title.
Each section looks like:
### 05:00 - 05:59
- `05:03` Subtitle text
- `05:07` Another subtitle line
Frame Artifacts
- Default direct-capture output goes under
frames/.
- Prefer one representative PNG per requested timestamp.
- Read references/implementation.md for the compact rules.
- Read references/keyframe-reference.md when you need the detailed rationale behind HTML parsing, stream selection, timestamp handling, or ffmpeg flags.
- Read references/asr-fallback.md when native subtitles are missing or when the user explicitly requests local ASR output.
Endpoint Smoke
When the user wants screenshot endpoint validation instead of standalone PNG capture:
- Search the repo for
ffmpeg, __playinfo__, /api/bilibili/screenshot, ffmpeg-static, and captureBilibiliScreenshot.
- Prefer reusing an existing server-side screenshot endpoint over adding a new one.
- Run the smoke script against the repo root and video URL.
- Treat a
200 image/jpeg response for two timestamps as the minimum passing smoke test.
The smoke script should fail if a response is empty or does not look like a JPEG.
If the target repo already has scripts/smoke-bilibili.js, reuse it instead of duplicating logic.
Validation
Before finishing:
- Confirm the page title and page number match the requested URL.
- Confirm the subtitle list is non-empty when native subtitle output was requested.
- Confirm timestamps increase monotonically in the first few lines of
sectioned.md.
- Confirm the Markdown file exists on disk.
- If
subtitles.json was requested, confirm it exists and includes API-source metadata plus merged groups.
- If ASR fallback was requested, confirm
audio-16k.wav, asr.srt, and asr.json exist on disk.
- If Chinese translation was requested after ASR, confirm
asr.zh.srt exists and keeps the original timestamps.
- If PNG frames were requested, confirm the files exist under
frames/ or the requested output path.
- If smoke testing was requested, confirm the endpoint returns non-empty JPEGs and records
smoke-report.json.
- If native subtitle access, ASR fallback, and screenshot checks differ, report them separately instead of collapsing them into one status.
Failure Handling
- If no BV id can be parsed, fail clearly.
- If the requested
p= is out of range, fail clearly.
- If the subtitle track is missing, say the page currently exposes no subtitle track and then switch to the local ASR fallback when the task still requires subtitles.
- If login-gated subtitles still fail with a full cookie, ask for a fresh cookie or copied cURL request.
- If direct frame capture works but subtitle access fails, report them separately instead of collapsing them into one failure.
- If the screenshot endpoint works but subtitle access fails, report them separately instead of collapsing them into one failure.
- Do not claim that native subtitles were fetched when you actually switched to ASR.
- Do not claim that ASR was used unless you actually switched to ASR.
1---2name: bilibili-video-evidence3description: Collect evidence artifacts from a Bilibili video URL. Fetch native subtitles, save `sectioned.md`, write normalized `subtitles.json`, capture `frames/*.png`, optionally validate a repo-local screenshot endpoint with `smoke-report.json`, and fall back to a local `ffmpeg` + ASR workflow when a page exposes no usable subtitle track. Use when Codex needs a Bilibili evidence bundle from `videoUrl`, direct frame capture by timestamp, subtitle download, transcript sectioning, local subtitle generation as `.srt`, Chinese subtitle translation that preserves technical keywords, screenshot endpoint smoke testing, or login-gated subtitle handling.4---56# Bilibili Video Evidence78Collect evidence first. Write notes later.910## Workflow11121. Parse the BV id and optional `p=` page index from the user URL.132. Fetch native subtitles before considering ASR or summaries.143. If the page exposes no usable subtitle track, or the user explicitly asks for a local/offline subtitle path, switch to the local ASR fallback in [references/asr-fallback.md](references/asr-fallback.md).154. Write native subtitle artifacts with `scripts/bilibili_subtitle_to_md.py`, or write ASR fallback artifacts with `scripts/bilibili_audio_asr_to_srt.py` after the fallback decision is made.165. Capture direct frame artifacts with `scripts/capture_bilibili_screenshot.js` when the user wants PNG evidence files.176. Inspect the repo for an existing screenshot endpoint before adding code.187. Run `scripts/smoke_bilibili_endpoint.js` only when the task is specifically about validating a repo-local screenshot route.198. Report native subtitle access, ASR fallback status, and screenshot access separately.2021## Outputs2223- `sectioned.md`24- `subtitles.json`25- `audio-16k.wav`26- `asr.srt`27- `asr.zh.srt`28- `asr.json`29- `frames/*.png`30- optional `smoke-report.json`3132## Run3334Use:3536```bash37python scripts/bilibili_subtitle_to_md.py \38 --url "https://www.bilibili.com/video/BV1X7411F744?p=5" \39 --output "sectioned.md" \40 --json-output "subtitles.json"41```4243If Bilibili exposes no usable subtitle track, run the local ASR fallback:4445```bash46python scripts/bilibili_audio_asr_to_srt.py \47 --url "https://www.bilibili.com/video/BV1X7411F744?p=5" \48 --cookie-file "cookie.txt" \49 --output-dir "outputs/P05" \50 --model "small" \51 --device "cpu" \52 --compute-type "int8"53```5455When a Chinese subtitle translation is requested after ASR, keep the `.srt` numbering and timestamps unchanged, translate only the subtitle text, and preserve technical keywords in English. Read [references/asr-fallback.md](references/asr-fallback.md) for the exact fallback rules and prompt pattern.5657Capture a frame directly:5859```bash60node scripts/capture_bilibili_screenshot.js \61 "https://www.bilibili.com/video/BV15DG7zxENa/" \62 00:24 \63 --output=frames/intro.png64```6566Validate a repo-local screenshot endpoint:6768```bash69node scripts/smoke_bilibili_endpoint.js <repo-root> <bilibili-url> --timestamps=00:13,10:2570```7172## Cookie Handling7374- Prefer the full browser `Cookie` header over `SESSDATA` alone.75- Accept either `--cookie` or `--cookie-file`.76- If neither is passed, the subtitle script may fall back to `BILIBILI_COOKIE` or `BILIBILI_SESSION_TOKEN` from the environment.77- Strip a leading `Cookie:` prefix if the user pasted a raw header line.78- Try `x/player/v2` first and keep `x/player/wbi/v2` as a fallback source.79- The local ASR fallback may still need browser cookie state to resolve or fetch the media stream.80- If login-gated subtitle access still fails, ask for a fresh full `Cookie` header or `Copy as cURL`.81- Treat frame capture success and subtitle access as separate checks.8283## Subtitle Artifacts8485The subtitle script writes Markdown with:8687- video title88- source URL89- BV id and CID90- page index and page title91- subtitle language and subtitle URL92- subtitle count93- timeline sections grouped by fixed-length buckets9495If `--output` is omitted, the default Markdown filename is the sanitized video title.9697Each section looks like:9899```md100### 05:00 - 05:59101102- `05:03` Subtitle text103- `05:07` Another subtitle line104```105106## Frame Artifacts107108- Default direct-capture output goes under `frames/`.109- Prefer one representative PNG per requested timestamp.110- Read [references/implementation.md](references/implementation.md) for the compact rules.111- Read [references/keyframe-reference.md](references/keyframe-reference.md) when you need the detailed rationale behind HTML parsing, stream selection, timestamp handling, or ffmpeg flags.112- Read [references/asr-fallback.md](references/asr-fallback.md) when native subtitles are missing or when the user explicitly requests local ASR output.113114## Endpoint Smoke115116When the user wants screenshot endpoint validation instead of standalone PNG capture:1171181. Search the repo for `ffmpeg`, `__playinfo__`, `/api/bilibili/screenshot`, `ffmpeg-static`, and `captureBilibiliScreenshot`.1192. Prefer reusing an existing server-side screenshot endpoint over adding a new one.1203. Run the smoke script against the repo root and video URL.1214. Treat a `200 image/jpeg` response for two timestamps as the minimum passing smoke test.122 The smoke script should fail if a response is empty or does not look like a JPEG.123124If the target repo already has `scripts/smoke-bilibili.js`, reuse it instead of duplicating logic.125126## Validation127128Before finishing:1291301. Confirm the page title and page number match the requested URL.1312. Confirm the subtitle list is non-empty when native subtitle output was requested.1323. Confirm timestamps increase monotonically in the first few lines of `sectioned.md`.1334. Confirm the Markdown file exists on disk.1345. If `subtitles.json` was requested, confirm it exists and includes API-source metadata plus merged groups.1356. If ASR fallback was requested, confirm `audio-16k.wav`, `asr.srt`, and `asr.json` exist on disk.1367. If Chinese translation was requested after ASR, confirm `asr.zh.srt` exists and keeps the original timestamps.1378. If PNG frames were requested, confirm the files exist under `frames/` or the requested output path.1389. If smoke testing was requested, confirm the endpoint returns non-empty JPEGs and records `smoke-report.json`.13910. If native subtitle access, ASR fallback, and screenshot checks differ, report them separately instead of collapsing them into one status.140141## Failure Handling142143- If no BV id can be parsed, fail clearly.144- If the requested `p=` is out of range, fail clearly.145- If the subtitle track is missing, say the page currently exposes no subtitle track and then switch to the local ASR fallback when the task still requires subtitles.146- If login-gated subtitles still fail with a full cookie, ask for a fresh cookie or copied cURL request.147- If direct frame capture works but subtitle access fails, report them separately instead of collapsing them into one failure.148- If the screenshot endpoint works but subtitle access fails, report them separately instead of collapsing them into one failure.149- Do not claim that native subtitles were fetched when you actually switched to ASR.150- Do not claim that ASR was used unless you actually switched to ASR.