From ee18cde745b0b2f31e4b4fcfd2e504741c2d2fa1 Mon Sep 17 00:00:00 2001 From: OpenClaw Agent Date: Fri, 6 Feb 2026 20:42:11 +0800 Subject: [PATCH] feat: Add /kb-add command for quick video addition - Add cmd_add() function to support adding single videos to inbox - Support BV IDs, full URLs, and short links (with friendly warning) - Add --process flag to immediately process after adding - Add --yes flag to skip confirmation prompts - Update SKILL.md with /kb-add command documentation --- skills/obsidian-kb/SKILL.md | 38 ++++++++++ skills/obsidian-kb/src/cli.py | 130 ++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/skills/obsidian-kb/SKILL.md b/skills/obsidian-kb/SKILL.md index fc9a157..8bbf4ea 100644 --- a/skills/obsidian-kb/SKILL.md +++ b/skills/obsidian-kb/SKILL.md @@ -11,6 +11,7 @@ | 命令 | 描述 | 用法 | |------|------|------| +| `/kb-add` | 添加单个视频 | `/kb-add [--process] [--yes]` | | `/kb-subscribe` | 订阅内容源 | `/kb-subscribe ::` | | `/kb-inbox` | 查看收件箱 | `/kb-inbox [--limit N]` | | `/kb-process` | 处理内容 | `/kb-process [content_id]` | @@ -20,6 +21,43 @@ ## 命令详解 +### /kb-add + +快速添加单个视频到收件箱。 + +**用法:** +``` +/kb-add BV1xx411c7mD +/kb-add "https://www.bilibili.com/video/BV1xx411c7mD" +/kb-add "https://www.bilibili.com/video/BV1xx411c7mD" --process +/kb-add BV1xx411c7mD --yes +``` + +**参数:** +- `` - 视频URL或BV号 + - 完整URL: `https://www.bilibili.com/video/BVxxxxx` + - BV号: `BVxxxxx` + - 短链接: `https://b23.tv/xxxxx`(显示友好提示) +- `--process` - 添加后立即处理 +- `--yes` - 跳过确认提示 + +**输出示例:** +``` +📥 正在添加视频: BV1xx411c7mD + → 标题: Python编程入门教程 + → UP主: CodeMaster + → 时长: 3600秒 + → 获取字幕... ✅ + +✅ 视频已添加到收件箱! + Content ID: abc123def456 + +💡 使用以下命令处理: + python3 src/cli.py process abc123def456 + 或: + python3 src/cli.py process all +``` + ### /kb-subscribe 订阅一个内容源,支持自动获取更新。 diff --git a/skills/obsidian-kb/src/cli.py b/skills/obsidian-kb/src/cli.py index 99adb8b..918f7cb 100644 --- a/skills/obsidian-kb/src/cli.py +++ b/skills/obsidian-kb/src/cli.py @@ -18,6 +18,7 @@ try: from src.storage import Storage from src.pipeline import ProcessingPipeline from src.models import ContentStatus + from src.sources.bilibili import BilibiliAdapter CONFIG_AVAILABLE = True except ImportError as e: print(f"Import warning: {e}", file=sys.stderr) @@ -102,6 +103,110 @@ def cmd_subscribe(args: argparse.Namespace): return 0 +def cmd_add(args: argparse.Namespace): + """Handle add command - add a single video to inbox.""" + print_header("Add Video to Inbox") + + if not CONFIG_AVAILABLE: + print("Error: Required modules not available. Please check installation.") + return 1 + + # Import here to avoid issues if not available + from src.models import ContentStatus + + url = args.url + + # Handle short links (b23.tv) + if 'b23.tv' in url: + print(f" ⚠️ 检测到短链接: {url}") + print(f" 💡 B站对短链接有反爬虫保护,请提供:") + print(f" 1. 完整URL: https://www.bilibili.com/video/BVxxxxx") + print(f" 2. 或BV号: BVxxxxx") + print(f"\n 提示: 可以在浏览器打开短链接,从地址栏复制完整URL") + return 1 + + # Create adapter + adapter = BilibiliAdapter() + + # Extract video metadata + print(f" → 正在获取视频信息: {url}") + content = adapter.extract_content(url) + if not content: + print(" ❌ 无法提取视频信息") + return 1 + + print(f" → 标题: {content.title}") + print(f" → UP主: {content.author}") + print(f" → 时长: {content.duration}秒") + + # Get transcript + print(" → 正在获取字幕...") + transcript = adapter.get_transcript(content) + if transcript: + content.transcript = transcript + print(f" ✓ 字幕已获取 ({len(transcript)} 字符)") + else: + print(" ⚠️ 无法获取字幕") + + # Set status to CONFIRMED (ready to process) + content.status = ContentStatus.CONFIRMED + + # Confirm before saving (unless --yes) + if not args.yes: + print(f"\n📋 准备添加到收件箱:") + print(f" 标题: {content.title}") + print(f" UP主: {content.author}") + print(f" 时长: {content.duration}秒") + print(f" 字幕: {'有' if transcript else '无'}") + + if args.process: + print(f" 操作: 添加并立即处理") + else: + print(f" 操作: 仅添加到收件箱") + + confirm = input("\n确认添加? [Y/n]: ").strip().lower() + if confirm and confirm not in ('y', 'yes'): + print("❌ 已取消") + return 0 + + # Save to inbox + print("\n → 保存到收件箱...") + storage = Storage() + storage.save_content(content) + + print(f"\n✅ 视频已添加到收件箱!") + print(f" Content ID: {content.id}") + + # Process immediately if --process flag is set + if args.process: + print(f"\n🔄 开始处理内容...") + try: + from src.pipeline import ProcessingPipeline + from src.models import ContentStatus + + pipeline = ProcessingPipeline() + content_text = content.transcript or content.summary or "" + + result = pipeline.process_full(content, content_text) + storage.save_content(result) + + print(f" ✅ 处理完成") + print(f" 📄 笔记: {result.output_path or 'N/A'}") + print(f" 🏷️ 标签: {', '.join(result.tags)}") + except Exception as e: + print(f" ❌ 处理失败: {e}") + import traceback + traceback.print_exc() + return 1 + else: + print(f"\n💡 使用以下命令处理:") + print(f" python3 src/cli.py process {content.id}") + print(f" 或:") + print(f" python3 src/cli.py process all") + + return 0 + + def cmd_inbox(args: argparse.Namespace): """Handle inbox command - display pending items.""" print_header("Inbox Contents") @@ -427,6 +532,9 @@ def main(): formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: + %(prog)s add "BV1xx411c7mD" + %(prog)s add "https://www.bilibili.com/video/BV1xx411c7mD" --process + %(prog)s add "https://b23.tv/xxxxx" --yes %(prog)s subscribe bilibili fav 12345 --name="Tech Favorites" %(prog)s inbox --limit 10 --sort date %(prog)s process all --yes @@ -439,6 +547,28 @@ Examples: subparsers = parser.add_subparsers(dest='command', help='Available commands') + # add 子命令 + add_parser = subparsers.add_parser( + 'add', + aliases=['a'], + help='Add a single video to inbox' + ) + add_parser.add_argument( + 'url', + help='Video URL or BV ID (supports: BVxxxxx, full URL)' + ) + add_parser.add_argument( + '--process', + action='store_true', + help='Process immediately after adding' + ) + add_parser.add_argument( + '--yes', + action='store_true', + help='Skip confirmation prompts' + ) + add_parser.set_defaults(func=cmd_add) + # subscribe 子命令 subscribe_parser = subparsers.add_parser( 'subscribe',