| name | paper-talker |
| description | End-to-end academic video production pipeline: research topic to subtitled video on streaming platforms. Use when the user wants to: (1) set up PaperTalker environment, (2) generate academic videos from a topic via NotebookLM, (3) add subtitles and burn into video, (4) upload videos to Bilibili/Douyin/WeChat/Xiaohongshu/Kuaishou, (5) run full pipeline topic-to-published-video, (6) troubleshoot deps or auth issues, (7) search academic papers, (8) schedule daily automated paper reading. Triggers: paper talker, academic video, topic to video, generate video, notebooklm, video pipeline, subtitle, upload bilibili, batch publish, setup papertalker, schedule, openclaw. |
| metadata | {"openclaw":{"requires":{"bins":["python","conda"]},"cron":{"entry_point":"run_scheduled.py","setup_script":"setup_cron.py"}}} |
Paper Talker
End-to-end academic video production: Research Topic -> NotebookLM Video -> Subtitles -> Multi-Platform Publishing.
Automation Principles
This pipeline is designed for FULLY FIXED automation. Claude MUST follow these rules:
- ALWAYS run connectivity check first as a SEPARATE command. Before Phase 1, run
quick_video.py "topic" --check in its own Bash call with timeout=120000. Check the exit code. Only proceed to Phase 1 if exit code is 0. If it fails, notify the user with the error output and do NOT run the full pipeline.
- ALWAYS use
PYTHONUNBUFFERED=1 in addition to PYTHONIOENCODING=utf-8 for ALL Python invocations. Without this, output is fully buffered in non-TTY environments and the script appears to hang silently with 0 bytes output.
- Never ask for confirmation before running scripts. Run
quick_video.py and publish.py directly. These are non-destructive (they only create files in output/ and output_subtitled/).
- Always use
--no-confirm when running quick_video.py to skip all interactive prompts.
- Auth expired? Auto-handled.
quick_video.py --check and quick_video.py automatically call tools/auto_login.py when NotebookLM auth expires โ the user just needs to complete Google login in the popup browser.
- Be patient with long operations. Deep Research takes 10-20 min; video generation takes 10-30+ min. Total pipeline can exceed 30 minutes. Use
timeout=600000 for Bash calls (use run_in_background=true for very long waits). Do NOT interrupt or retry prematurely.
- Network errors are transient โ NEVER retry by creating a new notebook. When
quick_video.py fails due to network errors mid-pipeline, Claude MUST:
- Record the notebook ID (NID) and video task ID (TID) from the script output (printed early in the run)
- Use
--resume NID TID to continue polling the SAME task in the SAME notebook
- Do NOT rerun
quick_video.py "TOPIC" --no-confirm โ this creates a duplicate notebook and wastes resources
- Wait 2-3 minutes before resuming โ the task continues running on Google's servers regardless of client disconnection
- Can retry
--resume multiple times if network keeps dropping โ the task ID stays valid for 30 min
- Run Phase 1 then Phase 2 sequentially without asking. After
quick_video.py produces a video, immediately run publish.py to subtitle and upload.
- Only confirm for truly destructive actions: deleting user files, modifying account credentials, or force-pushing git. Everything else: just do it.
- Bilibili login is fully automated.
publish.py handles login via Python API โ displays a QR code directly in the terminal for the user to scan with Bilibili App. No interactive terminal menu, no external window. If API fails, falls back to biliup CLI in a new terminal (Windows: biliup.exe, macOS: biliup-macos).
- Subtitle deduplication + verification is automatic. After transcription,
publish.py removes duplicates, converts TraditionalโSimplified Chinese, removes garbled text, fixes timing issues. No manual intervention needed.
- WeChat ่ง้ขๅท upload runs in an isolated subprocess (
src/workers/weixin_upload_worker.py) using async Playwright to avoid event loop conflicts. Login is handled via persistent browser profile; QR scan only needed on first use. Scan-then-hang recovery: automatic page reload if QR disappears but page stays on login URL.
- Platform uploads run concurrently (ๅ
็ปๅ
ไผ ). Each platform's login + upload runs in its own thread. The first platform to complete login immediately starts uploading while others are still logging in.
- Login polling is fast (0.2s intervals). All QR scan polling loops use 0.2s intervals for near-instant detection when user scans. 3-level URL re-verification uses 0.3s+0.5s (total 0.8s) to confirm login while avoiding false positives.
- One-command full pipeline:
quick_video.py "topic" --publish generates video AND auto-publishes. Supports --publish bilibili weixin_channels for specific platforms.
- Cross-platform: Windows (biliup.exe), macOS (biliup-macos), Linux (biliup) binaries in
vendor/.
Claude Execution Workflow (MANDATORY)
Claude MUST execute the pipeline in these exact steps. Do NOT skip or combine steps.
Step 0: Connectivity Check (SEPARATE Bash call, short timeout)
cd "<PROJECT_ROOT>" && PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u quick_video.py "TOPIC" --check
- timeout: 240000 (4 minutes max)
- If exit code != 0: STOP. Show the error output to the user. Do NOT proceed.
- If exit code == 0: proceed to Step 1.
- If auto-login is triggered (browser popup), wait for user to complete Google login.
Step 1: Generate Video (long-running, background recommended)
cd "<PROJECT_ROOT>" && PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u quick_video.py "TOPIC" --no-confirm
- timeout: 1200000. For longer waits, use
run_in_background=true and check with TaskOutput.
- CRITICAL: Record NID and TID from output. The script prints notebook ID (after "็ฌ่ฎฐๆฌ:") and video task ID (after "่ง้ขไปปๅก:") early in the run. Save these โ you need them for
--resume if the script fails.
- If exit code is non-zero due to network errors: proceed to Step 1b (Resume). Do NOT rerun this command.
- If exit code is non-zero for other reasons (auth, dependency): show output and stop.
Step 1b: Resume Failed Generation (if Step 1 failed due to network)
If Step 1 failed due to consecutive network errors but the notebook and video task were already submitted:
cd "<PROJECT_ROOT>" && PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u quick_video.py "TOPIC" --resume NID TID
- Replace
NID with the notebook ID and TID with the video task ID from Step 1 output.
- Wait at least 2-3 minutes before resuming โ the task continues on Google's servers regardless of client disconnection.
- Can retry
--resume multiple times if network keeps dropping โ the task ID stays valid for 30 min.
- Video generation typically takes 10-30+ minutes total; be patient.
Step 2: Subtitle + Upload (long-running, separate Bash call)
cd "<PROJECT_ROOT>" && PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u publish.py
- timeout: 1200000
- Check exit code. Report results (BV number, etc.) to user.
Pipeline Overview
PREFLIGHT (Step 0: quick_video.py --check)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Verify NotebookLM conn โ
โ โโ Auth file exists? โ
โ โโ Token valid? โ
โ โโ API reachable? โ
โ โโ Auto-login if needed โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ exit 0 = ok
UPSTREAM (Phase 1: quick_video.py) DOWNSTREAM (Phase 2: publish.py)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Research Topic โ โ output/*.mp4 โ
โ โ โ โ โ โ
โ NotebookLM โ โ 1. Extract Audio (FFmpeg) โ
โ โโ Deep Research โ โ 2. Extract Cover (1st frame)โ
โ โโ Paper Search (8 DBs) โ โ 3. Transcribe (whisper GPU) โ
โ โโ Manual Upload โ โ 4. Generate SRT (chunked) โ
โ โโ Mixed โ โ 5. Burn Subtitles (FFmpeg) โ
โ โ โ โ 6. Upload (Bilibili, ...) โ
โ Generate & Download MP4 โ โโโโโโโโ> โ 7. Cleanup + Save History โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ output/ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
output_subtitled/YYYY-MM-DD/
Human Interaction Points (Minimal)
The pipeline requires human action at exactly three points (only when auth is missing/expired):
| When | Action | Duration | Frequency |
|---|
| NotebookLM auth expired | Complete Google login in popup browser | ~30s | Rare (tokens last weeks) |
| Bilibili cookies missing | Scan terminal QR code with Bilibili App; intermediate status shown (scanned/confirming) | ~10s | Rare (cookies last months) |
| WeChat ่ง้ขๅท auth expired | Scan QR code in popup browser; 3s re-verify avoids false positives; instant detection on success | ~30s | Rare (persistent browser profile) |
Everything else is fully automated โ no confirmation prompts, no menu selections, no manual file operations.
Project Structure
PaperTalker-CLI/
โโโ CLAUDE.md # Project-level instructions for Claude Code
โโโ quick_video.py # Phase 1: topic -> NotebookLM video (async)
โโโ publish.py # Phase 2: subtitle + upload (canonical copy)
โโโ src/workers/weixin_upload_worker.py # WeChat Channels upload subprocess (async Playwright)
โโโ src/utils/paper_search.py # Literature search wrapper (uses skills/literature-review)
โโโ video.md # Video generation prompt (strict academic rigor)
โโโ schedule.txt # Daily schedule: tab-separated format with completion tracking
โโโ run_scheduled.py # Cron entry point: pick topic -> Phase 1 -> Phase 2 (supports --pre-hook/--post-hook)
โโโ auto_tracker.py # Auto paper discovery: literature search -> schedule.txt
โโโ setup_cron.py # OpenClaw cron registration helper (10 AM default)
โโโ OPENCLAW.md # OpenClaw handoff document (architecture + usage + TODO)
โโโ run_history.json # Completed schedule run records
โโโ run_history.txt # Simple text log of completed schedule runs
โโโ .env / .env.example # Proxy + API keys (HTTPS_PROXY, NCBI_API_KEY, SS_API_KEY, WECHAT_*)
โโโ setup/ # One-click installers
โ โโโ setup.bat / setup.ps1 # Windows (calls sub-scripts below)
โ โโโ setup.sh # macOS/Linux
โ โโโ setup_conda.bat # Step 1: detect/install Conda + Tsinghua mirrors
โ โโโ setup_env.bat # Step 2: create papertalker env (Python 3.11)
โ โโโ install_deps.bat # Step 3: install pip deps + Playwright chromium
โโโ tools/ # Utility scripts
โ โโโ auto_login.py # Non-interactive NotebookLM login helper
โ โโโ verify.py # Dependency verification checker
โโโ cookies/ # Authentication credentials (gitignored)
โ โโโ bilibili/account.json # Bilibili auth
โ โโโ weixin/storage_state.json # WeChat ่ง้ขๅท Playwright auth
โโโ vendor/ # Binary tools (gitignored)
โ โโโ biliup.exe # Bilibili login/upload (Windows)
โ โโโ biliup-macos # Bilibili login/upload (macOS)
โโโ output/ # Raw videos (cleared after downstream)
โโโ output_subtitled/ # Subtitled videos organized by date
โ โโโ YYYY-MM-DD/ # {topic}.mp4, {topic}.srt
โโโ deps/
โ โโโ notebooklm-py/ # NotebookLM Python client (v0.3.2, local editable)
โ โ โโโ src/notebooklm/ # Client API: notebooks, sources, artifacts, research, chat
โ โโโ paper-search-mcp/ # (legacy, replaced by literature-review skill)
โโโ skills/literature-review/ # Academic paper search skill
โ โโโ scripts/paper_search.py # SemanticScholarSearcher, ArxivSearcher, CrossRefSearcher
โโโ skills/paper-talker/ # Skill definition (distributable)
โโโ SKILL.md
โโโ scripts/publish.py # Phase 2 copy (for skill distribution)
โโโ references/ # Setup, upstream, downstream, known issues, etc.
Key Implementation Choices
| Component | Used (Tested) | Alternative (Not in Pipeline) |
|---|
| Transcription | faster-whisper GPU preferred (large-v3 float16), CPU fallback (small int8), isolated subprocess, parallel chunked transcription (default 3 workers) | Doubao ASR (permission issues) |
| Subtitle burn | FFmpeg subtitles filter | VectCutAPI (needs manual JianYing export) |
| Upload | biliup library direct import (vendor/biliup.exe for login) | โ |
| FFmpeg binary | imageio-ffmpeg pip package | conda install ffmpeg (GBK crash) |
Environment
| Item | Value |
|---|
| Conda env | papertalker (Python 3.11) |
| Project root | (auto-detected from script location) |
| Proxy | Set in .env (required for Google) |
| NotebookLM auth | ~/.notebooklm/storage_state.json |
| Bilibili cookies | cookies/bilibili/account.json |
| WeChat ่ง้ขๅท auth | cookies/weixin/storage_state.json |
| WeChat ๅ
ฌไผๅท API | .env (WECHAT_APPID, WECHAT_APPSECRET) |
Running Python
Both Phase 1 and Phase 2 MUST use the papertalker conda environment. Never use conda run (GBK crash).
CRITICAL: Always set PYTHONUNBUFFERED=1 (or use -u flag) to prevent silent output buffering in non-TTY environments (subprocess, pipe). Without this, scripts appear to hang with 0 bytes output.
PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u script.py
conda activate papertalker && PYTHONUNBUFFERED=1 python -u script.py
Directory Convention
| Directory | Purpose |
|---|
output/ | Raw videos from upstream. Cleared after downstream processing. |
output_subtitled/YYYY-MM-DD/ | Final subtitled videos + SRT files |
Pre-flight Check
Before running either phase, verify dependencies:
import importlib, os, sys
from pathlib import Path
checks = []
for mod, pkg in [
('notebooklm', 'notebooklm-py'), ('playwright', 'playwright'),
('dotenv', 'python-dotenv'), ('imageio_ffmpeg', 'imageio-ffmpeg'),
('faster_whisper', 'faster-whisper'), ('biliup', 'biliup'),
('jieba', 'jieba'),
]:
try:
importlib.import_module(mod)
checks.append(('ok', pkg))
except ImportError:
checks.append(('MISS', pkg))
try:
import imageio_ffmpeg
imageio_ffmpeg.get_ffmpeg_exe()
checks.append(('ok', 'ffmpeg-binary'))
except Exception:
checks.append(('MISS', 'ffmpeg-binary'))
auth = Path.home() / '.notebooklm' / 'storage_state.json'
checks.append(('ok' if auth.exists() else 'MISS', 'notebooklm-auth'))
for status, name in checks:
print(f" {'ok' if status == 'ok' else 'MISS':6s} {name}")
Fix Missing Dependencies
setup\setup.bat
./setup/setup.sh
pip install -e deps/notebooklm-py
pip install -e deps/paper-search-mcp
pip install python-dotenv httpx rich playwright
python -m playwright install chromium
pip install imageio-ffmpeg faster-whisper jieba "biliup>=1.1.29"
Authentication
NotebookLM (auto-handled by quick_video.py):
When auth expires, the script automatically launches tools/auto_login.py which opens a browser. The user completes Google login; the script auto-detects completion and saves credentials. No terminal interaction needed.
Manual fallback if auto-login fails:
conda activate papertalker
python tools/auto_login.py
Bilibili (auto-handled by publish.py):
When cookies are missing, publish.py calls Bilibili's TV QR login API directly (Python):
- Requests a QR code from Bilibili's API
- Renders the QR code in the terminal via
qrcode library (ASCII art)
- User scans with Bilibili App โ no menu selection needed
- Polls every 0.5s for login completion; shows intermediate status (
โ ๅทฒๆซ็ ! ่ฏทๅจๆๆบไธ็นๅปใ็กฎ่ฎค็ปๅฝใ) when QR is scanned but not yet confirmed (API codes 86039/86090)
- Saves cookies to
cookies/bilibili/account.json immediately on success (240s timeout)
If the Python API fails, falls back to launching biliup CLI in a new terminal window (cross-platform: Windows/macOS/Linux).
Manual fallback if auto-login fails:
cd vendor
./biliup.exe -u ../cookies/bilibili/account.json login
For full setup (Conda install, Tsinghua mirrors, env creation), see references/setup.md.
Phase 1: Video Generation (Upstream)
Script: quick_video.py โ async pipeline using Google NotebookLM.
conda activate papertalker
PYTHONUNBUFFERED=1 python -u quick_video.py "่ๆ็ป่" --check
PYTHONUNBUFFERED=1 python -u quick_video.py "่ๆ็ป่" --no-confirm
PYTHONUNBUFFERED=1 python -u quick_video.py "่ๆ็ป่" --no-confirm --publish bilibili weixin_channels
PYTHONUNBUFFERED=1 python -u quick_video.py "ไธป้ข" --source file --files paper.pdf --no-confirm --publish
PYTHONUNBUFFERED=1 python -u quick_video.py "่็ฝ่ดจๆๅ " --source search --no-confirm --publish
Upstream Pipeline
Step 0: Connectivity check (quick_video.py --check)
Step 1: Create NotebookLM notebook (title = topic)
Step 2: Gather sources (based on --source mode)
Step 3: Auto-confirm and proceed (--no-confirm skips interactive prompts)
Step 4: Import sources into notebook (batch 15, URL fallback)
Step 5: Wait for source processing (30s + 5s/source, max 180s)
Step 6: Generate video (submit task + poll status, up to 30 min)
Step 7: Download MP4 to output/{topic}_{timestamp}.mp4
Source Modes
| Mode | Behavior | Command Example |
|---|
research (default) | NotebookLM Deep Research auto-searches web | python quick_video.py "็็ฉๆบ่ฝไฝ" |
search | literature-review skill (Semantic Scholar + arXiv + CrossRef); auto-translates Chinese queries | python quick_video.py "่็ฝ่ดจๆๅ " --source search --platforms arxiv semantic_scholar --year 2024 |
upload | Opens notebook URL for manual file upload | python quick_video.py "้ๅญ่ฎก็ฎ" --source upload |
mixed | Deep Research + literature-review search combined | python quick_video.py "LLM่ฏ็ฉๅ็ฐ" --source mixed --platforms semantic_scholar |
file | Import local files (PDF/txt/md/docx) | python quick_video.py "Attention" --source file --files paper.pdf ./papers/ |
paper | Search by paper title, pick from candidates | python quick_video.py "Transformer" --source paper |
Key Parameters
| Parameter | Default | Description |
|---|
topic | (required) | Video topic |
--check | false | Only test NotebookLM connectivity, do not generate video |
--source | research | Source mode: research/search/upload/mixed/file/paper |
--style | whiteboard | 9 styles: whiteboard, classic, anime, kawaii, watercolor, retro_print, heritage, paper_craft, auto |
--lang | zh-CN | Language code |
--mode | deep | Deep Research depth: fast/deep |
--platforms | arxiv semantic_scholar | Paper search: arxiv, semantic_scholar, crossref |
--max-results | 10 | Per-platform result limit |
--year | none | Paper year filter |
--output | ./output | Video output directory |
--timeout | 3600 | Generation timeout (seconds) |
--instructions | video.md | Custom video prompt (override video.md) |
--no-confirm | false | Skip stage confirmations |
--resume NID TID | โ | Resume timed-out video task |
--files | โ | File/directory paths for --source file mode (PDF/txt/md/docx) |
--publish | โ | Auto-publish after generation (e.g. --publish bilibili weixin_channels) |
For full parameter reference, see references/upstream.md.
Video Generation Prompt (video.md)
Default prompt enforces strict academic rigor:
- Simplified Chinese output
- Must cite specific values (p-values, accuracy, AUC, confidence intervals)
- Include original figures, formulas from source papers
- High information density for researchers/graduate students
- Forbids vague language ("ๆพ่ๆๅ" forbidden โ must give exact numbers)
Output
Videos saved as output/{sanitized_topic}_{YYYYMMDD_HHMMSS}.mp4. Deep Research takes 10-20 min; video generation takes 10-30+ min. If timeout or network failure, use --resume NID TID to continue polling.
Phase 2: Post-Production & Publishing (Downstream)
Script: publish.py (project root) โ scans output/, processes all videos.
conda activate papertalker
PYTHONUNBUFFERED=1 python -u publish.py
Or with direct path (Windows):
PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1 "$(conda info --base)/envs/papertalker/python.exe" -u publish.py
Script options:
--skip-upload
--platforms bilibili weixin_channels weixin_article
--input output/
--output output_subtitled/
--workers 3
Supported platforms:
bilibili - Bilibili (B็ซ) video upload
douyin - Douyin (ๆ้ณ) - not yet implemented
weixin_channels - WeChat Video Channel (ๅพฎไฟก่ง้ขๅท) via Playwright browser automation
weixin_article - WeChat Official Account (ๅพฎไฟกๅ
ฌไผๅท) article publishing via API
xiaohongshu - Xiaohongshu (ๅฐ็บขไนฆ) - not yet implemented
kuaishou - Kuaishou (ๅฟซๆ) - not yet implemented
Downstream 7-Step Pipeline
| Step | Action | Details |
|---|
| 1 | Extract Audio | FFmpeg -> 16kHz mono WAV |
| 2 | Extract Cover | First frame of original (un-subtitled) video as JPEG; dual FFmpeg approach for robustness |
| 3 | Transcribe | faster-whisper in isolated subprocess(es); GPU (large-v3 float16) preferred, CPU (small int8) fallback; parallel chunked (default 3 workers, --workers N): splits audio into overlapping chunks, transcribes in parallel, merges with timestamp alignment; MKL env vars auto-set; auto-deduplicates consecutive identical/near-identical segments |
| 3b | Verify | Second-pass subtitle verification: TraditionalโSimplified Chinese conversion, garbled text removal, duplicate dedup, timing fixes, short-segment cleanup |
| 4 | Generate SRT | Smart chunking: jieba word-aware split, max 18 chars/line, word-level time alignment |
| 5 | Burn Subtitles | FFmpeg subtitles filter (Microsoft YaHei, white + black outline, MarginV=30) |
| 6 | Upload | Auto-generated title/desc/tags, cover image, per platform |
| 7 | Cleanup | Delete original + WAV + cover temp, save run history JSON |
Modular Scripts (ๆ้่ฐ็จ)
For fine-grained control, use standalone scripts in src/:
| Script | Description | Example |
|---|
src/transcribe.py | Audio extraction + Whisper transcription + SRT generation | python src/transcribe.py video.mp4 |
src/transcribe.py | Parallel transcription (3 workers default) | python src/transcribe.py video.mp4 --workers 3 |
src/subtitle.py | Burn SRT subtitles into video | python src/subtitle.py video.mp4 subtitles.srt |
src/upload_bilibili.py | Upload to Bilibili with metadata | python src/upload_bilibili.py video.mp4 --title "ๆ ้ข" --tags "tag1,tag2" --cover cover.jpg |
src/upload_weixin.py | Upload to WeChat Channels | python src/upload_weixin.py video.mp4 --title "ๆ ้ข" --desc "ๆ่ฟฐ" |
Use cases:
- Re-transcribe with different model:
python src/transcribe.py video.mp4 --model large-v3 --device cuda
- Parallel transcribe (faster on CPU):
python src/transcribe.py video.mp4 --workers 3
- Re-upload with different metadata:
python src/upload_bilibili.py video.mp4 --title "ๆฐๆ ้ข" --tags "ๆฐๆ ็ญพ"
- Subtitle-only workflow:
python src/transcribe.py video.mp4 && python src/subtitle.py video.mp4 video.srt
- Upload-only workflow:
python src/upload_bilibili.py video.mp4 --title "ๆ ้ข" --tags "tag1,tag2" --auto-login
Note: publish.py orchestrates these scripts internally. Use modular scripts when you need to retry a specific step or customize parameters.
Smart Metadata Generation
The script auto-generates B็ซ-optimized metadata from the filename:
- Topic extraction:
่ๆ็ป่_20260303_223817.mp4 -> ่ๆ็ป่ (strip _YYYYMMDD_HHMMSS)
- Title:
ใAI็ง็ ็งๆฎใ{topic}๏ผๅๆฒฟ็ ็ฉถๆทฑๅบฆ่งฃ่ฏป (max 80 chars)
- Description: Topic + duration + subtitle count + hashtags (max 250 chars)
- Tags: Self-adaptive based on topic content. Domain keyword detection (AI/Bio/Physics/etc.) adds relevant field tags. Splits compound topics (ไธ/ๅ/ๅ/+/&). Max 12 tags.
- Example:
Claude Code -> Claude Code,Anthropic,AIๅทฅๅ
ท,็ผ็จ,ๅผๅๅทฅๅ
ท,AI็ง็ ,...
- Example:
่็ฝ่ดจๆๅ ไธ่ฏ็ฉๅ็ฐ -> ่็ฝ่ดจๆๅ ไธ่ฏ็ฉๅ็ฐ,่็ฝ่ดจๆๅ ,่ฏ็ฉๅ็ฐ,็็ฉไฟกๆฏๅญฆ,...
- Cover: First frame of original (un-subtitled) video as JPEG; dual FFmpeg approach for robustness
- Category: tid=201 (็งๅญฆ็งๆฎ)
Subtitle Smart Chunking
Long whisper segments are split for screen readability:
- Parallel transcription (new): audio split into N overlapping chunks (3s overlap), each transcribed in separate subprocess, merged with timestamp alignment and overlap deduplication
- Verification (new): second-pass checks โ TraditionalโSimplified Chinese, garbled text removal, duplicate dedup, timing fixes, short-segment cleanup
- Deduplication: consecutive identical or near-identical segments are merged (Whisper/VAD artifact); removed count is logged
- Punctuation split (highest priority): ๏ผใใ๏ผ๏ผ๏ผ๏ผ,.;!?:
- Word-boundary split (via
jieba): never breaks mid-word (e.g. "ๆดป็็" stays intact)
- Max 18 Chinese characters per subtitle line
- Max 6 seconds display per subtitle entry
- Word-level time alignment: each subtitle's start/end derived from Whisper word timestamps (not proportional guessing)
- Fallback: proportional time distribution when word timestamps unavailable
- Example: 210 raw segments -> 295 display-ready subtitles
Dependency: pip install jieba (Chinese word segmentation, pure Python, no C deps)
Run History
Each run is recorded in references/run_history.json (last 50 records):
{
"date": "2026-03-03T23:22:47",
"topic": "่ๆ็ป่",
"file": "่ๆ็ป่_20260303_223817",
"subtitles": 295,
"duration": "9:39",
"title": "ใAI็ง็ ็งๆฎใ่ๆ็ป่๏ผๅๆฒฟ็ ็ฉถๆทฑๅบฆ่งฃ่ฏป",
"tags": "่ๆ็ป่,AI็ง็ ,ๅญฆๆฏ็งๆฎ,่ฎบๆ่งฃ่ฏป,ๅๆฒฟ็ ็ฉถ,ๆทฑๅบฆ่งฃ่ฏป",
"uploads": {"bilibili": "ok:BV1wjAfztECV"}
}
On startup, shows last successful run for reference.
Output Naming
Output files use clean topic names (timestamps stripped):
output_subtitled/YYYY-MM-DD/{topic}.mp4 # subtitled video
output_subtitled/YYYY-MM-DD/{topic}.srt # subtitle file
Manual Step-by-Step
For debugging or custom workflows, see references/downstream.md.
For VectCutAPI (JianYing editable subtitles), see references/vectcut_api.md.
For Doubao ASR (cloud alternative to whisper), see references/doubao_asr.md.
WeChat Publishing
่ง้ขๅท (Video Channels) โ Playwright automation
Login and upload are handled via Playwright browser automation:
- Login: Directly navigates to
https://channels.weixin.qq.com/platform/post/create. If not logged in, WeChat automatically redirects to login page. After QR scan, WeChat automatically redirects back to create page. Polls every 0.5s for URL change from login to post/create (5 min timeout). No complex URL stability checks needed โ WeChat handles the redirect flow.
- Upload:
upload_weixin_channels() runs in isolated subprocess (src/workers/weixin_upload_worker.py) using async Playwright. Uploads video, fills title (6-16 chars, auto-padded if < 6) + description, clicks publish button (tries 3 methods: direct click, force click, JS click). Waits for URL redirect to post/list to confirm publish success, then keeps browser open 35s to ensure request completes.
Usage: python publish.py --platforms weixin_channels
ๅ
ฌไผๅท (Official Account) โ API
Requires .env config:
WECHAT_APPID=your_appid
WECHAT_APPSECRET=your_appsecret
4-step API flow:
GET /cgi-bin/token โ access token (2h TTL)
POST /cgi-bin/material/add_material โ upload cover image
POST /cgi-bin/draft/add โ create article draft (title + description + B็ซ่ง้ข้พๆฅ + SRTๆๅญ็จฟ)
POST /cgi-bin/freepublish/submit โ publish draft
Usage: python publish.py --platforms weixin_article
Best combined: python publish.py --platforms bilibili weixin_channels weixin_article (bilibili first to get BV number for article)
Scheduling & OpenClaw Integration
schedule.txt
Tab-separated format with completion tracking:
# Columns: date topic source_mode platforms max_results status completed_at notes
# Legal values:
# date: YYYY-MM-DD or "queue"
# source_mode: research, search, file, paper, upload, mixed
# platforms: bilibili, douyin, weixin_channels, weixin_article, xiaohongshu, kuaishou (comma-separated)
# max_results: 1-50
# status: pending, completed, failed
#
# Source Mode Categories:
# 1. NotebookLM ๆฃ็ดข: research (Deep/Fast Research), mixed (Research + ๆ็ฎๆฃ็ดข)
# 2. ่ชไธปๆ็ฎๆฃ็ดข: search (Semantic Scholar + arXiv + CrossRef), paper (ๆๆ ้ขๆ็ดข้ๆฉ)
# 3. ๆฌๅฐๆไปถ: file (ๅฏผๅ
ฅ PDF/txt/md/docx), upload (ๆๅจไธไผ )
2026-03-10 ่็ฝ่ดจๆๅ search bilibili,weixin_channels 5 pending
queue ๅ็ป่ๆตๅบ research bilibili,weixin_channels 5 pending
queue LLM Agent research bilibili,weixin_channels 5 pending
- Date-bound topics: Exact match on today's date (highest priority)
- Queue entries: FIFO list (used when no date match)
- Status tracking: Automatically marked as
completed or failed after execution
- History: Completed runs logged to
run_history.txt
run_scheduled.py
Entry point for cron/automated runs:
python run_scheduled.py
python run_scheduled.py --dry-run
python run_scheduled.py --force "topic"
python run_scheduled.py --skip-phase2
python run_scheduled.py --json
python run_scheduled.py --publish-platforms bilibili weixin_channels
python run_scheduled.py --source-args '{"year": 2025}'
python run_scheduled.py --pre-hook "auto_tracker.py --write-schedule"
python run_scheduled.py --post-hook "notify.py"
Exit codes: 0 = success, 1 = failure (for cron/OpenClaw integration).
Flow: pre-hook โ pick_topic() โ Phase 1 (quick_video, in-process async) โ Phase 2 (publish.py, subprocess) โ mark_completed() โ post-hook
auto_tracker.py
Weekly hot topic paper tracker using literature-review skill (Semantic Scholar + arXiv).
Runs weekly, ranks by citation count, distributes topics across next 7 days (one per day).
python auto_tracker.py
python auto_tracker.py --write-schedule
python auto_tracker.py --write-schedule --force
python auto_tracker.py --status
python auto_tracker.py --days 180 --top 5
python auto_tracker.py --json
python auto_tracker.py --domains 0,2
Key behavior:
- 6-day cooldown between runs (use
--force to override)
- Source mode:
research (NotebookLM web search, the default)
- Skips dates that already have user-specified pending entries
- Records run history to
tracker_history.txt
Tracked domains (cross-AI):
- 0: ่ฟ็ค+AI (tumor cancer)
- 1: ่ ้+AI (gut microbiome)
- 2: ๅ็ป่+AI (single-cell RNA-seq)
- 3: ็ฉบ้ด่ฝฌๅฝ็ป+AI (spatial transcriptomics)
setup_cron.py
Register OpenClaw cron job:
python setup_cron.py
python setup_cron.py --execute
python setup_cron.py --with-tracker --execute
python setup_cron.py --time "14:30"
python setup_cron.py --tracker-time "08:00"
Known Issues
See references/known_issues.md for full list. Critical:
| Issue | Fix |
|---|
| Python output buffering (0 bytes in subprocess) | PYTHONUNBUFFERED=1 + -u flag for all invocations |
conda run GBK crash | Direct Python path + PYTHONIOENCODING=utf-8 |
conda install ffmpeg fails | pip install imageio-ffmpeg |
| FFmpeg subtitle Windows paths | path.replace('\\','/').replace(':','\\:') |
CUDA crash with word_timestamps=True in function scope | Subprocess transcribe (auto in publish.py) |
MKL mkl_malloc memory failure on CPU | Set MKL_THREADING_LAYER=sequential, OMP_NUM_THREADS=1 before import; use small model on CPU |
| biliup login interactive | Auto-handled: publish.py uses Python API for QR login (terminal QR code, no menu). Falls back to biliup CLI if API fails. Cross-platform: biliup.exe (Win), biliup-macos (Mac) |
| Whisper duplicate segments | Auto-handled: verify_segments() merges duplicates, converts T2S, removes garbled text, fixes timing |
| WeChat ่ง้ขๅท login detection | Direct navigate to post/create URL. If on login page, poll every 0.2s for URL change. 3-level re-verify (0.3s+0.5s) avoids false positives. Auto-reload if page stuck after QR scan |
| WeChat ่ง้ขๅท file chooser | Use set_input_files() instead of expect_file_chooser() โ more stable in non-interactive environments |
| WeChat ่ง้ขๅท publish button | Try 3 click methods (direct, force, JS). Wait for URL redirect to post/list to confirm success. Keep browser open 70s after publish |
| WeChat ่ง้ขๅท short title < 6 chars | Auto-pad with "โ่ง้ข่งฃ่ฏป" to meet 6-char minimum |
| Playwright chromium version mismatch | python -m playwright install chromium (or upgrade playwright to match existing browser) |
| Network errors during video generation | Do NOT create a new notebook. Record NID+TID from output, wait 2-3 min, then --resume NID TID |
| NotebookLM auth expired | Auto-handled: quick_video.py calls tools/auto_login.py automatically |
| Doubao ASR 45000030 permission | Use faster-whisper local GPU instead |
| Chinese queries return 0 results | Auto-translated to English by paper_search.py (~60 academic term mappings) |
| paper-search-mcp replaced | Use skills/literature-review (Semantic Scholar + arXiv + CrossRef) via src/utils/paper_search.py |
| biliup < 1.0 blocked (21590) | pip install "biliup>=1.1.29" |
login_by_cookies KeyError | Pass full account dict, NOT account['cookie_info'] |
| BiliBili(data) initialization | Must pass Data object, then call bili.login_by_cookies(account) separately. Do NOT pass cookie_data as constructor arg |
| B็ซ tag format (code 21001) | data.tag must be comma-separated string, NOT list. Use data.tag = ','.join(tags) after Data() construction (__post_init__ only converts at init time) |
| B็ซ preupload returns 412/empty | Session cookies not loaded โ ensure login_by_cookies() is called before upload_file() |
| biliup API QR request fails | JSON parse error on auth_code endpoint โ intermittent. Falls back to biliup.exe CLI (requires interactive terminal) |
| NotebookLM video generation fails with 20 sources | Too many sources can cause "failed" status. Use --max-results 5 (10 total from 2 platforms) for reliability |
Progress Display
Pre-flight check:
ok imageio-ffmpeg / faster-whisper / biliup / ffmpeg / cookies
Last run: 2026-03-03 | ่ๆ็ป่ | bilibili: ok:BV1wjAfztECV
Scanning output/... found N videos.
Date folder: output_subtitled/2026-03-03/
--- [1/N] ่ๆ็ป่_20260303_223817.mp4 ---
Topic: ่ๆ็ป่
[1/7] Extract audio......... ok
[2/7] Extract cover......... ok -> ่ๆ็ป่_cover.jpg
[3/7] Transcribe............ ok (210 segments, 9:39) [3 workers]
Verify: 2 fixes applied
T2S: 'ๅญธ็ฟ' -> 'ๅญฆไน '
removed 1 duplicate segments
[4/7] Generate SRT.......... ok (295 subtitles) -> 2026-03-03/่ๆ็ป่.srt
[5/7] Burn subtitles........ ok -> 2026-03-03/่ๆ็ป่.mp4
[6/7] Upload:
Title: ใAI็ง็ ็งๆฎใ่ๆ็ป่๏ผๅๆฒฟ็ ็ฉถๆทฑๅบฆ่งฃ่ฏป
Tags: ่ๆ็ป่,AI็ง็ ,ๅญฆๆฏ็งๆฎ,่ฎบๆ่งฃ่ฏป,ๅๆฒฟ็ ็ฉถ,ๆทฑๅบฆ่งฃ่ฏป
Bilibili ok BV1wjAfztECV
[7/7] Cleanup............... ok (original + temp deleted)
Resources