- Add _normalize_metadata() to flatten nested metadata structure
- Fix generate_frontmatter() to use correct metadata fields
- Change _sanitize_filename() to return standardized "bilibili_{bvid}" format
Fixes: analysis.md frontmatter showing "未命名"/0/"未知" instead of actual values
Fixes: audio filename using video title instead of platform_bvid format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Handle Whisper transcription format (array of segments with text)
- Extract full text from transcription array before passing to DeepAnalyzer
- Fix offsets parsing to support both dict and list formats
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add download_video() to BilibiliAdapter using yt-dlp
- Add bilibili_cookie config to Settings
- Update DownloadProcessor to call video download for bilibili videos
- Add idempotency check to ASRProcessor for existing subtitle files
- Fix indentation error in asr.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- When content_type is video and no official subtitle available:
- Download video using yt-dlp
- Extract audio for Whisper fallback
- Update content_file with actual video path
This enables the pipeline to handle videos that don't have
official Bilibili subtitles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add content_dir field to ASRInput schema
- Pass content_dir from pipeline when creating ASRInput
- Modify _try_official_subtitle to use content_dir for output
- Modify _run_whisper_basic to use content_dir for output
- Add validation for empty video_path in Whisper fallback
Root cause: DownloadProcessor sets content_file="" for video types,
causing Path("").parent to resolve to current directory instead of
content directory. Subtitle files were written to wrong location.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse duration strings like "12:34" or "01:23:45" into seconds.
Previously only integer duration values were handled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AnalyzeProcessor wraps existing DeepAnalyzer for pipeline integration
- Loads metadata and content from JSON files
- Generates analysis reports as Markdown with frontmatter
- Records state on success and failure
- Supports both video and article content types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TDD GREEN phase:
- DownloadProcessor downloads article/answer/zhuanlan content
- Video content is skipped (handled by ASR in Phase 3)
- Content files saved with correct naming convention
- DownloadProcessor exported from kb_pipeline.processors
- All 17 tests pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TDD GREEN phase:
- DownloadProcessor inherits from BaseProcessor
- Fetches metadata from Bilibili and Zhihu adapters
- Saves metadata to content_dir as JSON
- Records state on success/failure
- Skips step if already completed (idempotency)
- All metadata tests pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ParseProcessor wraps LinkParser for URL parsing
- Returns ParseOutput with platform, content_type, content_id
- Records state when state_manager is provided
- Handles unknown URLs with success=False
- Export BaseProcessor, ParseProcessor, ASRProcessor from __init__.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Test BaseProcessor cannot be instantiated directly
- Test subclass must implement process() method
- Test state_manager attribute is provided
- Test STEP_NAME class attribute requirement
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create processors module with ASRProcessor class
- Implement _try_official_subtitle for B站字幕下载
- Support process() method with subtitle-first strategy
- Add helper functions for whisper.cpp integration
- All 5 processor tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>