bilinote-cli 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/.gitignore +1 -0
  2. bilinote_cli-0.1.3/CHANGELOG.md +15 -0
  3. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/PKG-INFO +8 -5
  4. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/README.md +7 -4
  5. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/pyproject.toml +1 -1
  6. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/cli.py +98 -57
  7. bilinote_cli-0.1.2/CHANGELOG.md +0 -8
  8. bilinote_cli-0.1.2/CHANGELOG.md.tmp +0 -0
  9. bilinote_cli-0.1.2/publish.command +0 -72
  10. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  11. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/.github/ISSUE_TEMPLATE//346/226/260/345/242/236/345/212/237/350/203/275/345/273/272/350/256/256.md" +0 -0
  12. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/.github/workflows/docker-build.yml +0 -0
  13. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/.github/workflows/main.yml +0 -0
  14. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/BiliNote.shortcut +0 -0
  15. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/CLAUDE.md +0 -0
  16. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/LICENSE +0 -0
  17. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/README.en.md +0 -0
  18. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/dev-docs//345/216/206/345/217/262/350/256/260/345/275/225/345/222/214/351/207/215/350/257/225/346/234/215/345/212/241/350/256/276/350/256/241.md" +0 -0
  19. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/dev-docs//345/217/221/345/270/203/345/210/260 githubTODO.md" +0 -0
  20. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/dev-docs//345/221/275/345/220/215/346/226/271/345/274/217.md" +0 -0
  21. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/__init__.py +0 -0
  22. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/config_manager.py +0 -0
  23. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/decorators/__init__.py +0 -0
  24. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/decorators/timeit.py +0 -0
  25. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/__init__.py +0 -0
  26. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/base.py +0 -0
  27. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/bilibili_downloader.py +0 -0
  28. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/common.py +0 -0
  29. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/douyin_downloader.py +0 -0
  30. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/douyin_helper/abogus.py +0 -0
  31. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/kuaishou_downloader.py +0 -0
  32. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/kuaishou_helper/__init__.py +0 -0
  33. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/kuaishou_helper/kuaishou.py +0 -0
  34. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/local_downloader.py +0 -0
  35. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/xiaoyuzhoufm_download.py +0 -0
  36. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/youtube_downloader.py +0 -0
  37. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/downloaders/youtube_subtitle.py +0 -0
  38. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/enmus/exception.py +0 -0
  39. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/enmus/note_enums.py +0 -0
  40. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/enmus/task_status_enums.py +0 -0
  41. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/exceptions/__init__.py +0 -0
  42. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/exceptions/biz_exception.py +0 -0
  43. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/exceptions/note.py +0 -0
  44. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/exceptions/provider.py +0 -0
  45. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/__init__.py +0 -0
  46. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/base.py +0 -0
  47. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/gpt_factory.py +0 -0
  48. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/prompt.py +0 -0
  49. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/prompt_builder.py +0 -0
  50. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/provider/OpenAI_compatible_provider.py +0 -0
  51. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/request_chunker.py +0 -0
  52. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/universal_gpt.py +0 -0
  53. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/gpt/utils.py +0 -0
  54. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/__init__.py +0 -0
  55. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/audio_model.py +0 -0
  56. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/gpt_model.py +0 -0
  57. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/model_config.py +0 -0
  58. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/notes_model.py +0 -0
  59. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/pipeline_model.py +0 -0
  60. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/process_config.py +0 -0
  61. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/provide_model.py +0 -0
  62. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/transcriber_model.py +0 -0
  63. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/models/video_record.py +0 -0
  64. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/secret_manager.py +0 -0
  65. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/__init__.py +0 -0
  66. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/batch_processor.py +0 -0
  67. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/cache/__init__.py +0 -0
  68. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/cache/task_cache.py +0 -0
  69. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/constant.py +0 -0
  70. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/note.py +0 -0
  71. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/pipeline/__init__.py +0 -0
  72. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/pipeline/ai_processor.py +0 -0
  73. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/pipeline/preparer.py +0 -0
  74. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/postprocessing.py +0 -0
  75. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/searcher.py +0 -0
  76. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/services/serial_executor.py +0 -0
  77. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/__init__.py +0 -0
  78. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/base.py +0 -0
  79. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/bcut.py +0 -0
  80. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/groq.py +0 -0
  81. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/kuaishou.py +0 -0
  82. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/transcriber_provider.py +0 -0
  83. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/transcriber/whisper_cpp.py +0 -0
  84. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/cookie_helper.py +0 -0
  85. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/env_checker.py +0 -0
  86. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/file_cleanup.py +0 -0
  87. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/logger.py +0 -0
  88. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/note_helper.py +0 -0
  89. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/path_helper.py +0 -0
  90. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/screenshot_marker.py +0 -0
  91. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/status_code.py +0 -0
  92. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/url_parser.py +0 -0
  93. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/video_helper.py +0 -0
  94. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/utils/video_reader.py +0 -0
  95. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/validators/__init__.py +0 -0
  96. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/app/validators/video_url_validator.py +0 -0
  97. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/__init__.py +0 -0
  98. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/config.yaml.example +0 -0
  99. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/dev_config.json +0 -0
  100. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/model_config_manager.py +0 -0
  101. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/models.json +0 -0
  102. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/config/transcriber.json +0 -0
  103. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/src/ffmpeg_helper.py +0 -0
  104. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/__init__.py +0 -0
  105. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/conftest.py +0 -0
  106. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/integration/test_transcriber_integration.py +0 -0
  107. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/downloaders/test_bilibili_downloader.py +0 -0
  108. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/downloaders/test_cookie_helper.py +0 -0
  109. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/downloaders/test_douyin_downloader.py +0 -0
  110. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/downloaders/test_kuaishou_downloader.py +0 -0
  111. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/gpt/test_request_chunker.py +0 -0
  112. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/gpt/test_universal_gpt_checkpoint.py +0 -0
  113. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/services/test_searcher.py +0 -0
  114. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/services/test_task_serial_executor.py +0 -0
  115. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/transcriber/test_transcriber_fallback.py +0 -0
  116. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_note_helper.py +0 -0
  117. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_path_helper.py +0 -0
  118. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_screenshot_marker.py +0 -0
  119. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_url_parser.py +0 -0
  120. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_video_helper.py +0 -0
  121. {bilinote_cli-0.1.2 → bilinote_cli-0.1.3}/tests/unit/utils/test_video_reader_dedupe.py +0 -0
@@ -1,6 +1,7 @@
1
1
  # macOS
2
2
  .DS_Store
3
3
  publish.sh
4
+ publish.command
4
5
  TODO.md
5
6
 
6
7
  # Python
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+
4
+ ## [0.1.3] - 2026-05-19
5
+ ### Changed
6
+ - search 指令改为输出 json 文件,由 process 指令对 json 文件中的视频链接进行批量处理。
7
+
8
+
9
+ ## [0.1.2] - 2026-05-17
10
+ ### Changed
11
+ - search 指令后的批量记笔记功能,支持并行处理
12
+
13
+ ## [0.1.1] - 2026-05-15
14
+ ### Added
15
+ - 首次发布至 PyPI
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bilinote-cli
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: AI 视频笔记生成 CLI 工具
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -87,10 +87,11 @@ bilinote process "<url>" --screenshot --link --style 学术风
87
87
  bilinote process "<url>" --video-understanding --model gpt-4o
88
88
 
89
89
  # 自定义输出目录
90
- bilinote process "<url>" --output-dir ./notes/
90
+ bilinote process "<url>" --output-dir <dir>
91
91
 
92
- # 搜索视频
93
- bilinote search "Python 教程" --platform bilibili
92
+ # 搜索视频(结果保存为 json)
93
+ bilinote search "Python 教程" --platform bilibili --output-dir <dir>
94
+ bilinote process --json "<search_result.json>" --index 2 3 8
94
95
 
95
96
  # 其他命令
96
97
  bilinote model-list # 列出可用模型
@@ -117,7 +118,7 @@ bilinote install-shortcut # 安装 macOS 快捷指令(推荐)
117
118
  | 命令 | 说明 |
118
119
  |------|------|
119
120
  | `process <url>` | 处理视频生成笔记 |
120
- | `search <keyword>` | 搜索视频并批量生成 |
121
+ | `search <keyword>` | 并保存结果为 JSON |
121
122
  | `model-list` | 列出可用模型 |
122
123
  | `model-set-default <model>` | 设置默认模型 |
123
124
  | `config set <key> <value>` | 设置密钥 |
@@ -136,6 +137,8 @@ bilinote install-shortcut # 安装 macOS 快捷指令(推荐)
136
137
  | `--style` | 笔记风格:学术风、口语风等 |
137
138
  | `--video-understanding` | 启用多模态理解 |
138
139
  | `--output-dir` | 输出目录路径 |
140
+ | `--json` | 处理 json 文件的路径 |
141
+ | `--index` | 处理 json 文件中的链接序号 |
139
142
 
140
143
  ## 【指南】提取 Safari Cookie
141
144
 
@@ -66,10 +66,11 @@ bilinote process "<url>" --screenshot --link --style 学术风
66
66
  bilinote process "<url>" --video-understanding --model gpt-4o
67
67
 
68
68
  # 自定义输出目录
69
- bilinote process "<url>" --output-dir ./notes/
69
+ bilinote process "<url>" --output-dir <dir>
70
70
 
71
- # 搜索视频
72
- bilinote search "Python 教程" --platform bilibili
71
+ # 搜索视频(结果保存为 json)
72
+ bilinote search "Python 教程" --platform bilibili --output-dir <dir>
73
+ bilinote process --json "<search_result.json>" --index 2 3 8
73
74
 
74
75
  # 其他命令
75
76
  bilinote model-list # 列出可用模型
@@ -96,7 +97,7 @@ bilinote install-shortcut # 安装 macOS 快捷指令(推荐)
96
97
  | 命令 | 说明 |
97
98
  |------|------|
98
99
  | `process <url>` | 处理视频生成笔记 |
99
- | `search <keyword>` | 搜索视频并批量生成 |
100
+ | `search <keyword>` | 并保存结果为 JSON |
100
101
  | `model-list` | 列出可用模型 |
101
102
  | `model-set-default <model>` | 设置默认模型 |
102
103
  | `config set <key> <value>` | 设置密钥 |
@@ -115,6 +116,8 @@ bilinote install-shortcut # 安装 macOS 快捷指令(推荐)
115
116
  | `--style` | 笔记风格:学术风、口语风等 |
116
117
  | `--video-understanding` | 启用多模态理解 |
117
118
  | `--output-dir` | 输出目录路径 |
119
+ | `--json` | 处理 json 文件的路径 |
120
+ | `--index` | 处理 json 文件中的链接序号 |
118
121
 
119
122
  ## 【指南】提取 Safari Cookie
120
123
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bilinote-cli"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "AI 视频笔记生成 CLI 工具"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -5,6 +5,7 @@ import argparse
5
5
  import sys
6
6
  import os
7
7
  import json
8
+ import re
8
9
  import subprocess
9
10
  from pathlib import Path
10
11
 
@@ -109,9 +110,15 @@ def main():
109
110
  # 处理本地视频
110
111
  python cli.py process ./video.mp4
111
112
 
112
- # 搜索视频并交互选择批量生成笔记
113
+ # 搜索视频并保存结果
113
114
  python cli.py search "关键词" --platform bilibili
114
115
 
116
+ # 从搜索结果处理全部视频
117
+ python cli.py process --json ~/.bilinote/output/search_result/xxx.json
118
+
119
+ # 从搜索结果选择指定序号处理
120
+ python cli.py process --json ~/.bilinote/output/search_result/xxx.json --index 1 2 3
121
+
115
122
  # 查看任务状态
116
123
  python cli.py status <task_id>
117
124
 
@@ -140,9 +147,14 @@ def main():
140
147
  subparsers = parser.add_subparsers(dest='command', help='可用命令')
141
148
 
142
149
  # process 子命令 - 处理视频生成笔记
143
- process_parser = subparsers.add_parser('process', help='处理视频生成笔记(支持批量 URL)',
150
+ process_parser = subparsers.add_parser('process', help='处理视频生成笔记(支持批量 URL 或 JSON)',
144
151
  parents=[_SHARED_ARGS_PARSER])
145
- process_parser.add_argument('video_urls', nargs='+', help='视频链接或本地文件路径(可多个)')
152
+ process_parser.add_argument('video_urls', nargs='*', default=[],
153
+ help='视频链接或本地文件路径(可多个,与 --json 二选一)')
154
+ process_parser.add_argument('--json', dest='json_path', default=None,
155
+ help='从 search 结果 JSON 文件读取链接')
156
+ process_parser.add_argument('--index', nargs='+', type=int, default=None,
157
+ help='指定 JSON 中要处理的视频序号(如 --index 1 2 3)')
146
158
  process_parser.add_argument('--platform',
147
159
  choices=['bilibili', 'youtube', 'douyin', 'kuaishou', 'local'],
148
160
  help='视频平台(可选,默认自动识别)')
@@ -150,14 +162,13 @@ def main():
150
162
  process_parser.add_argument('--output-dir', default=None, help='批量输出目录(多任务时自动创建批次目录)')
151
163
 
152
164
  # search 子命令 - 搜索视频
153
- search_parser = subparsers.add_parser('search', help='搜索视频并交互选择批量执行',
154
- parents=[_SHARED_ARGS_PARSER])
165
+ search_parser = subparsers.add_parser('search', help='搜索视频并保存结果为 JSON')
155
166
  search_parser.add_argument('keyword', help='搜索关键词')
156
167
  search_parser.add_argument('--platform', default='bilibili',
157
168
  choices=['bilibili', 'youtube'],
158
169
  help='搜索平台(默认 bilibili)')
159
- search_parser.add_argument('--model', default=None, help='模型名称')
160
- search_parser.add_argument('--output-dir', default=None, help='批量输出目录')
170
+ search_parser.add_argument('--output-dir', default=None,
171
+ help='搜索结果保存目录(默认 ~/.bilinote/output/search_result)')
161
172
 
162
173
  # status 子命令 - 查询任务状态
163
174
  status_parser = subparsers.add_parser('status', help='查询任务状态')
@@ -264,25 +275,33 @@ def main():
264
275
 
265
276
 
266
277
  def process_video_cli(args):
267
- """处理视频生成笔记(支持批量)"""
278
+ """处理视频生成笔记(支持批量 URL 或 JSON)"""
268
279
  video_urls = args.video_urls
269
-
270
- # 使用默认模型
280
+ json_path = args.json_path
281
+
282
+ if not video_urls and not json_path:
283
+ print('错误: 请提供视频链接或使用 --json 指定搜索结果文件')
284
+ sys.exit(1)
285
+
286
+ if json_path and video_urls:
287
+ print('错误: 视频链接和 --json 不可同时使用')
288
+ sys.exit(1)
289
+
290
+ if json_path:
291
+ video_urls = _load_urls_from_json(json_path, args.index)
292
+
271
293
  model_name = args.model
272
294
  if not model_name:
273
295
  model_name = get_default_model()
274
296
  if not model_name:
275
297
  print('错误: 未配置默认模型,请使用 --model 指定模型或 model-set-default 设置默认模型')
276
298
  sys.exit(1)
277
-
278
- # 静态预检:API Key 是否存在
299
+
279
300
  if not _check_model_api_key(model_name):
280
301
  sys.exit(1)
281
-
282
- # 一键从 argparse namespace 生成 ProcessConfig(quality、format 等自动处理)
302
+
283
303
  cfg = ProcessConfig(**vars(args))
284
-
285
- # 构建任务列表
304
+
286
305
  items = []
287
306
  for url in video_urls:
288
307
  platform = args.platform or detect_platform(url)
@@ -291,11 +310,45 @@ def process_video_cli(args):
291
310
  continue
292
311
  task_id = extract_video_id(url, platform)
293
312
  items.append((url, platform, task_id, task_id))
294
-
313
+
295
314
  _process_tasks(items, cfg, model_name, args.output_dir)
296
315
  _show_shortcut_process_prompt()
297
316
 
298
317
 
318
+ def _load_urls_from_json(json_path: str, indices: list[int] | None = None) -> list[str]:
319
+ """从 search 结果 JSON 中读取链接列表"""
320
+ if not os.path.exists(json_path):
321
+ print(f"错误: 文件不存在: {json_path}")
322
+ sys.exit(1)
323
+
324
+ try:
325
+ with open(json_path, 'r', encoding='utf-8') as f:
326
+ data = json.load(f)
327
+ except json.JSONDecodeError as e:
328
+ print(f"错误: JSON 解析失败: {e}")
329
+ sys.exit(1)
330
+
331
+ results = data.get("results", [])
332
+ if not results:
333
+ print("错误: JSON 中无搜索结果")
334
+ sys.exit(1)
335
+
336
+ if indices:
337
+ index_set = set(indices)
338
+ selected = [r for r in results if r.get("index") in index_set]
339
+ not_found = index_set - {r.get("index") for r in results}
340
+ if not_found:
341
+ print(f"警告: 序号 {sorted(not_found)} 不在搜索结果中")
342
+ if not selected:
343
+ print("错误: 指定的序号无匹配结果")
344
+ sys.exit(1)
345
+ print(f"从 JSON 选择了 {len(selected)} 个视频(共 {len(results)} 条结果)")
346
+ return [r["link"] for r in selected]
347
+
348
+ print(f"从 JSON 加载全部 {len(results)} 个视频链接")
349
+ return [r["link"] for r in results]
350
+
351
+
299
352
  def _process_tasks(items: list, cfg: ProcessConfig, model_name: str, output_dir: str | None = None, batch_name: str | None = None):
300
353
  """统一任务处理入口
301
354
 
@@ -426,8 +479,9 @@ def _format_duration(seconds):
426
479
 
427
480
 
428
481
  def search_videos_cli(args):
429
- """搜索视频 → 交互选择 → 串行批量生成笔记"""
482
+ """搜索视频并保存结果为 JSON"""
430
483
  from app.services.searcher import search as searcher
484
+ from datetime import datetime
431
485
 
432
486
  platform = args.platform or "bilibili"
433
487
  keyword = args.keyword
@@ -435,13 +489,11 @@ def search_videos_cli(args):
435
489
  print(f"搜索: {keyword} 平台: {platform}")
436
490
  print("-" * 60)
437
491
 
438
- # 1. 搜索
439
492
  items = searcher(keyword, platform=platform)
440
493
  if not items:
441
494
  print("未找到相关视频")
442
495
  return
443
496
 
444
- # 2. 展示结果
445
497
  print(f"搜索到 {len(items)} 条结果:\n")
446
498
  for i, item in enumerate(items, 1):
447
499
  parts = [f"{i}. {item['title']}"]
@@ -458,46 +510,35 @@ def search_videos_cli(args):
458
510
  parts.append(" ".join(stats))
459
511
  print(" ".join(parts))
460
512
 
461
- # 3. 交互选择
462
- print(f"\n输入序号列表(如 1 2 4)以执行,q 退出:")
463
- user_input = input("> ").strip()
464
- if user_input.lower() == 'q':
465
- print("退出")
466
- return
467
-
468
- try:
469
- indices = [int(x) for x in user_input.split()]
470
- selected = [items[i - 1] for i in indices if 1 <= i <= len(items)]
471
- except (ValueError, IndexError):
472
- print("输入格式错误")
473
- return
474
-
475
- if not selected:
476
- print("未选择任何视频")
477
- return
513
+ search_result = {
514
+ "meta": {
515
+ "keyword": keyword,
516
+ "platform": platform,
517
+ "searched_at": datetime.now().isoformat(timespec="seconds"),
518
+ },
519
+ "results": [
520
+ {"index": i + 1, **item}
521
+ for i, item in enumerate(items)
522
+ ],
523
+ }
524
+
525
+ output_dir = args.output_dir or os.path.join(
526
+ os.path.expanduser("~"), ".bilinote", "output", "search_result"
527
+ )
528
+ os.makedirs(output_dir, exist_ok=True)
478
529
 
479
- # 4. 默认模型
480
- model_name = args.model or get_default_model()
481
- if not model_name:
482
- print("未配置默认模型,请先 --model-set-default")
483
- return
530
+ timestamp = datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
531
+ safe_keyword = re.sub(r'[^\w\s\u4e00-\u9fff]', '', keyword).strip().replace(' ', '_')[:30]
532
+ filename = f"{timestamp}_{safe_keyword}.json"
533
+ json_path = os.path.join(output_dir, filename)
484
534
 
485
- # 静态预检:API Key 是否存在
486
- if not _check_model_api_key(model_name):
487
- return
535
+ with open(json_path, 'w', encoding='utf-8') as f:
536
+ json.dump(search_result, f, ensure_ascii=False, indent=2)
488
537
 
489
- # 5. 准备任务列表并统一处理
490
- cfg = ProcessConfig(**vars(args))
491
-
492
- task_items = []
493
- for item in selected:
494
- url = item['link']
495
- detected_platform = detect_platform(url) or platform
496
- task_id = extract_video_id(url, detected_platform)
497
- title = item.get('title', task_id)
498
- task_items.append((url, detected_platform, task_id, title))
499
-
500
- _process_tasks(task_items, cfg, model_name, args.output_dir, batch_name=keyword)
538
+ print(f"\n搜索结果已保存至: {json_path}")
539
+ print(f"\n使用 process 命令处理搜索结果:")
540
+ print(f" bilinote process --json \"{json_path}\"")
541
+ print(f" bilinote process --json \"{json_path}\" --index 1 2 3")
501
542
 
502
543
 
503
544
  def list_models():
@@ -1,8 +0,0 @@
1
- # Changelog
2
-
3
- ## \[0.1.1] - 2026-05-15
4
-
5
- ### Added
6
-
7
- - 首次发布至 PyPI
8
-
File without changes
@@ -1,72 +0,0 @@
1
- set -e
2
-
3
- # ---------- 用户配置 ----------
4
- VERSION="0.1.2"
5
-
6
- # CHANGELOG 分类包括:Added Changed Removed Fixed Security
7
-
8
- CHANGELOG="### Changed
9
- - search 指令后的批量记笔记功能,支持并行处理
10
- "
11
-
12
- cd "$(dirname "$0")"
13
-
14
- # 检查 CHANGELOG 和版本是否已存在
15
- if [ -f CHANGELOG.md ]; then
16
- if grep -q "^## \[${VERSION}\]" CHANGELOG.md; then
17
- echo "版本已存在,跳过"
18
- exit 0
19
- fi
20
- else
21
- echo "# Changelog" > CHANGELOG.md
22
- fi
23
-
24
-
25
- # ---------- 自动修改 pyproject.toml ----------
26
- if [ ! -f pyproject.toml ]; then
27
- echo "错误:当前目录没有 pyproject.toml"
28
- exit 1
29
- fi
30
-
31
- # 替换 version 字段
32
- grep -q "^version" pyproject.toml || { echo "Error: 'version' line not found in pyproject.toml" >&2; exit 1; }
33
- sed -i.bak -E "s/^version.*/version = \"${VERSION}\"/" pyproject.toml
34
-
35
- rm -f pyproject.toml.bak # 删除备份文件
36
-
37
- echo "✓ pyproject.toml 版本号已更新为 ${VERSION}"
38
-
39
- # ---------- 自动更新 CHANGELOG.md ----------
40
- DATE=$(date +%Y-%m-%d)
41
- NEW_ENTRY="## [${VERSION}] - ${DATE}"$'\n'"${CHANGELOG}"
42
-
43
-
44
- # 使用 awk 在第一个 "## [数字" 行之前插入新条目(前后空行)
45
- awk -v new_entry="$NEW_ENTRY" '
46
- BEGIN { inserted = 0 }
47
- /^## \[[0-9]/ && !inserted {
48
- # 在匹配行之前先打印新条目(前后加空行)
49
- print ""
50
- print new_entry
51
- print ""
52
- inserted = 1
53
- }
54
- { print }
55
- END {
56
- # 如果没有匹配到任何版本标题,则在末尾追加新条目
57
- if (!inserted) {
58
- print ""
59
- print new_entry
60
- print ""
61
- }
62
- }' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
63
-
64
-
65
- echo "✓ CHANGELOG.md 已添加 ${VERSION} 版本的更新记录"
66
-
67
- # ---------- 原有发布流程 ----------
68
- rm -rf dist/
69
- uv build
70
- ls dist/
71
- export UV_PUBLISH_TOKEN="pypi-AgEIcHlwaS5vcmcCJGM1M2U5NThjLWQ4NTctNDBlNy04NDFhLTUzMTM4NTk0OTU2NwACFFsxLFsiYmlsaW5vdGUtY2xpIl1dAAIsWzIsWyJmN2Y4MzczOC1lMzlkLTQyOTgtODMyMS1mMTkxM2JhMDQxZDYiXV0AAAYg4oFE7cnbCFM5fV6HOB10sNzaBk84MYhbnZ6MWaT7Cu8"
72
- uv publish
File without changes
File without changes
File without changes