zhihu-toolkit 0.1.0__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.
- zhihu_toolkit-0.1.0/.github/workflows/ci.yml +35 -0
- zhihu_toolkit-0.1.0/.github/workflows/publish.yml +34 -0
- zhihu_toolkit-0.1.0/.gitignore +15 -0
- zhihu_toolkit-0.1.0/.pre-commit-config.yaml +7 -0
- zhihu_toolkit-0.1.0/LICENSE +21 -0
- zhihu_toolkit-0.1.0/PKG-INFO +225 -0
- zhihu_toolkit-0.1.0/README.md +165 -0
- zhihu_toolkit-0.1.0/autocomp.py +142 -0
- zhihu_toolkit-0.1.0/pyproject.toml +103 -0
- zhihu_toolkit-0.1.0/setup.cfg +4 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/__init__.py +19 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/__init__.py +25 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/_helpers.py +212 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/agora.py +636 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/ai.py +334 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/auth.py +291 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/browse.py +1003 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/chat.py +315 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/config.py +283 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/consult.py +394 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/convert.py +143 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/daemon.py +101 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/download.py +424 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/draft.py +313 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/interact.py +517 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/interact_comment_interactive.py +617 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/listen.py +63 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/people.py +369 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/profile.py +126 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/publish.py +108 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/scrape.py +145 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/search.py +118 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/stats.py +81 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/commands/tools.py +660 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/__init__.py +22 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/download_contents.py +744 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/__init__.py +104 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/_session_core.py +271 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/agora.py +337 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/ai_direct.py +426 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/article.py +79 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/auth_login.py +312 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/cache_manager.py +332 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/captcha.py +216 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat.py +917 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat_commands.py +91 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat_commands_builtin.py +271 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/collection.py +141 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/comments.py +325 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/consult.py +316 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/draft.py +252 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/feed.py +198 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/following.py +225 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/hot.py +52 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/imchat.py +175 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/notifications.py +54 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/people.py +398 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/pin.py +59 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/publishing.py +266 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/question.py +231 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/question_log.py +200 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/read_history.py +53 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/report.py +94 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/request_tool.py +142 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/requests.py +215 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/search.py +212 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/segment_comments.py +91 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/stats.py +132 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/upload_image.py +152 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/upvoter.py +71 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/waterfall.py +118 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/yanxuan.py +388 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/zvideo.py +214 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/universal_converter.py +130 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/__init__.py +6 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/html2markdown.py +505 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/markdown2html.py +41 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/wait.py +33 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/zse.py +618 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/__init__.py +0 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/_smoothing.py +39 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/analyze_monthly_income.py +156 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/derivative_analysis.py +77 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/growth_level.py +114 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_content_datas.py +286 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_daily_metrics.py +131 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_follower_detail.py +82 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_follower_profile.py +129 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_income_range.py +205 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_score_detail.py +159 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_zhihu_incomes.py +125 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_content_metrics.py +520 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_follower_detail.py +150 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_zhihu_incomes.py +83 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_zhihu_incomes_advanced.py +103 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/salt.py +252 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/stats_content_metrics.py +771 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/weekday_income_analysis.py +73 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/__init__.py +27 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/lifecycle.py +273 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/protocol.py +248 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/proxy.py +637 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/server.py +526 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/__init__.py +46 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/__init__.py +21 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/archiver.py +589 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/__init__.py +14 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/config.py +88 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/data_loader.py +50 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/dataset.py +190 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/discovery.py +145 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/model.py +175 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/text_cleaner.py +81 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/train.py +226 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/monitor.py +1063 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/main.py +67 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/__init__.py +17 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/cluster_visualizer.py +275 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/cooccurrence_network.py +236 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/count_answer_words.py +138 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/graph.py +750 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/stop_words.txt +83 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/wordcloud_generator.py +139 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/output.py +266 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/__init__.py +44 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/agora_vote.txt +12 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/commit_message.txt +1 -0
- zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/series_naming.txt +1 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/PKG-INFO +225 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/SOURCES.txt +134 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/dependency_links.txt +1 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/entry_points.txt +2 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/requires.txt +38 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/scm_file_list.json +130 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/scm_version.json +8 -0
- zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.13"
|
|
16
|
+
- run: pip install ruff==0.15.9
|
|
17
|
+
- run: ruff check .
|
|
18
|
+
- run: ruff format --check .
|
|
19
|
+
|
|
20
|
+
build:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0 # setuptools-scm 需要看到 tags
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.13"
|
|
29
|
+
- run: pip install build
|
|
30
|
+
- run: python -m build
|
|
31
|
+
# 数据文件必须打进 wheel,否则 import zhihu_cli 会崩
|
|
32
|
+
- name: Smoke-test packaged data files
|
|
33
|
+
run: |
|
|
34
|
+
pip install --no-deps dist/*.whl
|
|
35
|
+
python -c "from zhihu_cli.prompts import AGORA_VOTE_SYSTEM_PROMPT; from zhihu_cli.nlp_tools import STOP_WORDS; print('data files OK')"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write # 创建 GitHub Release
|
|
10
|
+
id-token: write # 向 PyPI 做 trusted publishing (OIDC)
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0 # setuptools-scm 需要看到 tags 来派生版本号
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
- run: pip install build
|
|
23
|
+
- run: python -m build
|
|
24
|
+
- name: Publish to PyPI
|
|
25
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
26
|
+
with:
|
|
27
|
+
attestations: true # SLSA 签名,需要 id-token: write
|
|
28
|
+
- name: Create GitHub Release
|
|
29
|
+
env:
|
|
30
|
+
GH_TOKEN: ${{ github.token }}
|
|
31
|
+
run: |
|
|
32
|
+
gh release create "$GITHUB_REF_NAME" dist/*.tar.gz dist/*.whl \
|
|
33
|
+
--title "$GITHUB_REF_NAME" \
|
|
34
|
+
--generate-notes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kris
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zhihu-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zhihu scraper and Markdown conversion utilities.
|
|
5
|
+
Author-email: KrisTHL181 <KrisTHL181@outlook.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/KrisTHL181/zhihu-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/KrisTHL181/zhihu-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/KrisTHL181/zhihu-cli/issues
|
|
10
|
+
Keywords: zhihu,scraper,cli,markdown,downloader,api
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: click
|
|
26
|
+
Requires-Dist: curl-cffi
|
|
27
|
+
Requires-Dist: lxml
|
|
28
|
+
Requires-Dist: cssselect
|
|
29
|
+
Requires-Dist: pyyaml
|
|
30
|
+
Requires-Dist: rich
|
|
31
|
+
Requires-Dist: aiomqtt
|
|
32
|
+
Requires-Dist: textual>=2.0
|
|
33
|
+
Requires-Dist: qrcode
|
|
34
|
+
Requires-Dist: Pillow
|
|
35
|
+
Provides-Extra: classifier
|
|
36
|
+
Requires-Dist: torch>=2.0.0; extra == "classifier"
|
|
37
|
+
Requires-Dist: transformers>=4.30.0; extra == "classifier"
|
|
38
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == "classifier"
|
|
39
|
+
Requires-Dist: jieba; extra == "classifier"
|
|
40
|
+
Requires-Dist: networkx; extra == "classifier"
|
|
41
|
+
Requires-Dist: numpy; extra == "classifier"
|
|
42
|
+
Provides-Extra: nlp
|
|
43
|
+
Requires-Dist: jieba; extra == "nlp"
|
|
44
|
+
Requires-Dist: matplotlib; extra == "nlp"
|
|
45
|
+
Requires-Dist: numpy; extra == "nlp"
|
|
46
|
+
Requires-Dist: pandas; extra == "nlp"
|
|
47
|
+
Requires-Dist: plotly; extra == "nlp"
|
|
48
|
+
Requires-Dist: scikit-learn; extra == "nlp"
|
|
49
|
+
Requires-Dist: wordcloud; extra == "nlp"
|
|
50
|
+
Requires-Dist: networkx; extra == "nlp"
|
|
51
|
+
Provides-Extra: creator
|
|
52
|
+
Requires-Dist: matplotlib; extra == "creator"
|
|
53
|
+
Requires-Dist: numpy; extra == "creator"
|
|
54
|
+
Requires-Dist: pandas; extra == "creator"
|
|
55
|
+
Requires-Dist: scipy; extra == "creator"
|
|
56
|
+
Requires-Dist: seaborn; extra == "creator"
|
|
57
|
+
Provides-Extra: notify
|
|
58
|
+
Requires-Dist: desktop-notifier; extra == "notify"
|
|
59
|
+
Dynamic: license-file
|
|
60
|
+
|
|
61
|
+
<div align="center">
|
|
62
|
+
|
|
63
|
+
# 🧢 zhihu-cli
|
|
64
|
+
|
|
65
|
+
**The terminal is your new Zhihu HQ.**
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
browse · download · search · publish · analyze — all from the command line.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
[](https://www.python.org/downloads/)
|
|
72
|
+
[](LICENSE)
|
|
73
|
+
[](https://github.com/KrisTHL181/zhihu-cli/stargazers)
|
|
74
|
+
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
**zhihu-cli** turns your terminal into a full-featured Zhihu client. Authenticate once, then browse, search, download, publish, and analyze — without ever opening a browser.
|
|
80
|
+
|
|
81
|
+
> ⚠️ This is an **unofficial** CLI for Zhihu. Use at your own risk. Not affiliated with Zhihu Inc.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 🚀 Quick Start
|
|
86
|
+
|
|
87
|
+
> **Requirement:** Python 3.12 or newer. Check your version with `python --version` before installing.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Install
|
|
91
|
+
pip install -e .
|
|
92
|
+
|
|
93
|
+
# Optional extras
|
|
94
|
+
pip install -e ".[nlp]" # word clouds, clustering
|
|
95
|
+
pip install -e ".[creator]" # income charts, trends
|
|
96
|
+
pip install -e ".[classifier]" # ML-powered content classification
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 1. Authenticate
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
zhihu auth paste # paste a cURL from browser DevTools
|
|
103
|
+
zhihu auth login # scan a QR code with the Zhihu App
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. Verify
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
zhihu auth status # check login status and active profile
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## ✨ What You Can Do
|
|
115
|
+
|
|
116
|
+
### 📖 Read & Browse
|
|
117
|
+
|
|
118
|
+
Browse Zhihu's feeds, hot lists, questions, articles, pins, and comments — all rendered in your terminal with a Rich-powered pager. Explore the real-time trending list with excerpts, scroll through your personalized recommend feed, or dive into a question and its full answer thread without clicking a single link.
|
|
119
|
+
|
|
120
|
+
### 💾 Download for Offline
|
|
121
|
+
|
|
122
|
+
Save any Zhihu content (articles, answers, questions, pins, videos) as clean Markdown with YAML frontmatter. Download individual pieces or batch-process from a manifest. Everything lands in `~/.zhihu-cli/downloads/`, organized by type, ready for your note-taking system or offline reading.
|
|
123
|
+
|
|
124
|
+
### 🔍 Search
|
|
125
|
+
|
|
126
|
+
Search questions, articles, users, and topics across Zhihu. Fine-tune result depth and quantity — all from the command line.
|
|
127
|
+
|
|
128
|
+
### ✍️ Publish & Edit
|
|
129
|
+
|
|
130
|
+
Write answers and articles in Markdown, publish them to Zhihu with one command. Need to update? Modify existing answers and articles from your local files. Markdown-to-HTML conversion happens automatically via Zhihu's own rendering pipeline.
|
|
131
|
+
|
|
132
|
+
### 💬 Interact
|
|
133
|
+
|
|
134
|
+
Vote, thank, follow, block, and comment — full social interaction without the browser. Manage collections: create, populate, and organize them. Send and receive direct messages, and stream real-time notifications and chat via MQTT.
|
|
135
|
+
|
|
136
|
+
### 🕸️ Scrape & Export
|
|
137
|
+
|
|
138
|
+
Batch-export your creations, activity history, answers, and articles as structured JSON. Use the universal converter to merge and normalize across formats for your own data pipeline.
|
|
139
|
+
|
|
140
|
+
### 📊 Analyze
|
|
141
|
+
|
|
142
|
+
**Creator analytics** — pull your Zhihu income data and visualize it: monthly summaries, trend charts (with EMA), advanced indicators (Bollinger Bands, MACD), derivative analysis (velocity/acceleration/jerk), weekday breakdowns, and per-content daily metrics. Charts are saved as PNGs.
|
|
143
|
+
|
|
144
|
+
**NLP tools** — run word frequency analysis, generate word clouds, and perform K-means clustering on your downloaded content. All operate across your full Markdown library.
|
|
145
|
+
|
|
146
|
+
### 🔐 Multi-Account
|
|
147
|
+
|
|
148
|
+
Save multiple profiles from different accounts, switch between them with a single command. Each profile keeps its own auth credentials and cookies.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 🏗️ Architecture
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
src/zhihu_cli/
|
|
156
|
+
├── main.py # Click CLI — command group hub
|
|
157
|
+
├── output.py # styled terminal output (Rich)
|
|
158
|
+
├── content/
|
|
159
|
+
│ ├── handlers/ # one file per Zhihu domain
|
|
160
|
+
│ └── utils/ # HTML↔Markdown, ZSE v4 signing
|
|
161
|
+
├── creator_tools/ # income analytics + plotting
|
|
162
|
+
├── nlp_tools/ # word count, wordcloud, clustering
|
|
163
|
+
└── extensions/ # plugin system (auto-discovered)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
| Layer | What It Does |
|
|
167
|
+
|---|---|
|
|
168
|
+
| **🔐 Auth** | Browser Cookie + User-Agent headers from cURL paste or QR code login, cached per-profile |
|
|
169
|
+
| **✍️ Signing** | Every Zhihu request gets auto-signed with `x-zse-93` / `x-zse-96` headers via ZSE v4 cipher |
|
|
170
|
+
| **🌐 Requests** | `curl_cffi` impersonates Chrome's TLS fingerprint to avoid detection |
|
|
171
|
+
| **📄 Extraction** | Prefers direct API calls; falls back to HTML page scraping with `js-initialData` parsing |
|
|
172
|
+
| **📝 Markdown** | HTML → LaTeX preprocessing → recursive traversal → clean Markdown. Reverse for publishing |
|
|
173
|
+
| **🔌 Extensions** | Drop a plugin in `extensions/` with `register_cli(group)` — auto-discovered at startup |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🧪 Extras
|
|
178
|
+
|
|
179
|
+
### Optional Dependencies
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install -e ".[nlp]" # jieba, matplotlib, wordcloud, scikit-learn...
|
|
183
|
+
pip install -e ".[creator]" # matplotlib, numpy, pandas, seaborn...
|
|
184
|
+
pip install -e ".[classifier]" # torch, transformers, scikit-learn...
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Shell Completions
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
eval "$(python autocomp.py)"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 🤝 Contributing
|
|
196
|
+
|
|
197
|
+
PRs welcome! The codebase is structured for extensibility:
|
|
198
|
+
|
|
199
|
+
- **New command?** Add a file to `commands/` with a `register_<name>(group)` function, import it in `main.py`.
|
|
200
|
+
- **New handler?** Add a file to `content/handlers/` — follow the existing patterns.
|
|
201
|
+
- **New extension?** Create `extensions/<name>/` with an `__init__.py` exposing `register_cli(group)`.
|
|
202
|
+
|
|
203
|
+
Run the formatter before submitting:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
pre-commit run --all-files
|
|
207
|
+
ruff check .
|
|
208
|
+
ruff format .
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📜 License
|
|
214
|
+
|
|
215
|
+
MIT
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
<div align="center">
|
|
220
|
+
|
|
221
|
+
*Made with ❤️ and way too many terminal sessions.*
|
|
222
|
+
|
|
223
|
+
[Report a bug](https://github.com/KrisTHL181/zhihu-cli/issues) · [Fork this repository](https://github.com/KrisTHL181/zhihu-cli/fork) · Star ⭐ this repo!
|
|
224
|
+
|
|
225
|
+
</div>
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🧢 zhihu-cli
|
|
4
|
+
|
|
5
|
+
**The terminal is your new Zhihu HQ.**
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
browse · download · search · publish · analyze — all from the command line.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
[](https://www.python.org/downloads/)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://github.com/KrisTHL181/zhihu-cli/stargazers)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
**zhihu-cli** turns your terminal into a full-featured Zhihu client. Authenticate once, then browse, search, download, publish, and analyze — without ever opening a browser.
|
|
20
|
+
|
|
21
|
+
> ⚠️ This is an **unofficial** CLI for Zhihu. Use at your own risk. Not affiliated with Zhihu Inc.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
> **Requirement:** Python 3.12 or newer. Check your version with `python --version` before installing.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Install
|
|
31
|
+
pip install -e .
|
|
32
|
+
|
|
33
|
+
# Optional extras
|
|
34
|
+
pip install -e ".[nlp]" # word clouds, clustering
|
|
35
|
+
pip install -e ".[creator]" # income charts, trends
|
|
36
|
+
pip install -e ".[classifier]" # ML-powered content classification
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 1. Authenticate
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
zhihu auth paste # paste a cURL from browser DevTools
|
|
43
|
+
zhihu auth login # scan a QR code with the Zhihu App
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Verify
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
zhihu auth status # check login status and active profile
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## ✨ What You Can Do
|
|
55
|
+
|
|
56
|
+
### 📖 Read & Browse
|
|
57
|
+
|
|
58
|
+
Browse Zhihu's feeds, hot lists, questions, articles, pins, and comments — all rendered in your terminal with a Rich-powered pager. Explore the real-time trending list with excerpts, scroll through your personalized recommend feed, or dive into a question and its full answer thread without clicking a single link.
|
|
59
|
+
|
|
60
|
+
### 💾 Download for Offline
|
|
61
|
+
|
|
62
|
+
Save any Zhihu content (articles, answers, questions, pins, videos) as clean Markdown with YAML frontmatter. Download individual pieces or batch-process from a manifest. Everything lands in `~/.zhihu-cli/downloads/`, organized by type, ready for your note-taking system or offline reading.
|
|
63
|
+
|
|
64
|
+
### 🔍 Search
|
|
65
|
+
|
|
66
|
+
Search questions, articles, users, and topics across Zhihu. Fine-tune result depth and quantity — all from the command line.
|
|
67
|
+
|
|
68
|
+
### ✍️ Publish & Edit
|
|
69
|
+
|
|
70
|
+
Write answers and articles in Markdown, publish them to Zhihu with one command. Need to update? Modify existing answers and articles from your local files. Markdown-to-HTML conversion happens automatically via Zhihu's own rendering pipeline.
|
|
71
|
+
|
|
72
|
+
### 💬 Interact
|
|
73
|
+
|
|
74
|
+
Vote, thank, follow, block, and comment — full social interaction without the browser. Manage collections: create, populate, and organize them. Send and receive direct messages, and stream real-time notifications and chat via MQTT.
|
|
75
|
+
|
|
76
|
+
### 🕸️ Scrape & Export
|
|
77
|
+
|
|
78
|
+
Batch-export your creations, activity history, answers, and articles as structured JSON. Use the universal converter to merge and normalize across formats for your own data pipeline.
|
|
79
|
+
|
|
80
|
+
### 📊 Analyze
|
|
81
|
+
|
|
82
|
+
**Creator analytics** — pull your Zhihu income data and visualize it: monthly summaries, trend charts (with EMA), advanced indicators (Bollinger Bands, MACD), derivative analysis (velocity/acceleration/jerk), weekday breakdowns, and per-content daily metrics. Charts are saved as PNGs.
|
|
83
|
+
|
|
84
|
+
**NLP tools** — run word frequency analysis, generate word clouds, and perform K-means clustering on your downloaded content. All operate across your full Markdown library.
|
|
85
|
+
|
|
86
|
+
### 🔐 Multi-Account
|
|
87
|
+
|
|
88
|
+
Save multiple profiles from different accounts, switch between them with a single command. Each profile keeps its own auth credentials and cookies.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 🏗️ Architecture
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
src/zhihu_cli/
|
|
96
|
+
├── main.py # Click CLI — command group hub
|
|
97
|
+
├── output.py # styled terminal output (Rich)
|
|
98
|
+
├── content/
|
|
99
|
+
│ ├── handlers/ # one file per Zhihu domain
|
|
100
|
+
│ └── utils/ # HTML↔Markdown, ZSE v4 signing
|
|
101
|
+
├── creator_tools/ # income analytics + plotting
|
|
102
|
+
├── nlp_tools/ # word count, wordcloud, clustering
|
|
103
|
+
└── extensions/ # plugin system (auto-discovered)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Layer | What It Does |
|
|
107
|
+
|---|---|
|
|
108
|
+
| **🔐 Auth** | Browser Cookie + User-Agent headers from cURL paste or QR code login, cached per-profile |
|
|
109
|
+
| **✍️ Signing** | Every Zhihu request gets auto-signed with `x-zse-93` / `x-zse-96` headers via ZSE v4 cipher |
|
|
110
|
+
| **🌐 Requests** | `curl_cffi` impersonates Chrome's TLS fingerprint to avoid detection |
|
|
111
|
+
| **📄 Extraction** | Prefers direct API calls; falls back to HTML page scraping with `js-initialData` parsing |
|
|
112
|
+
| **📝 Markdown** | HTML → LaTeX preprocessing → recursive traversal → clean Markdown. Reverse for publishing |
|
|
113
|
+
| **🔌 Extensions** | Drop a plugin in `extensions/` with `register_cli(group)` — auto-discovered at startup |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🧪 Extras
|
|
118
|
+
|
|
119
|
+
### Optional Dependencies
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pip install -e ".[nlp]" # jieba, matplotlib, wordcloud, scikit-learn...
|
|
123
|
+
pip install -e ".[creator]" # matplotlib, numpy, pandas, seaborn...
|
|
124
|
+
pip install -e ".[classifier]" # torch, transformers, scikit-learn...
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Shell Completions
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
eval "$(python autocomp.py)"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 🤝 Contributing
|
|
136
|
+
|
|
137
|
+
PRs welcome! The codebase is structured for extensibility:
|
|
138
|
+
|
|
139
|
+
- **New command?** Add a file to `commands/` with a `register_<name>(group)` function, import it in `main.py`.
|
|
140
|
+
- **New handler?** Add a file to `content/handlers/` — follow the existing patterns.
|
|
141
|
+
- **New extension?** Create `extensions/<name>/` with an `__init__.py` exposing `register_cli(group)`.
|
|
142
|
+
|
|
143
|
+
Run the formatter before submitting:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pre-commit run --all-files
|
|
147
|
+
ruff check .
|
|
148
|
+
ruff format .
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 📜 License
|
|
154
|
+
|
|
155
|
+
MIT
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
<div align="center">
|
|
160
|
+
|
|
161
|
+
*Made with ❤️ and way too many terminal sessions.*
|
|
162
|
+
|
|
163
|
+
[Report a bug](https://github.com/KrisTHL181/zhihu-cli/issues) · [Fork this repository](https://github.com/KrisTHL181/zhihu-cli/fork) · Star ⭐ this repo!
|
|
164
|
+
|
|
165
|
+
</div>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Shell autocompletion setup for the CLI tool.
|
|
4
|
+
|
|
5
|
+
Detects the current OS and shell, then prints the appropriate ``eval`` command
|
|
6
|
+
to enable Click-based shell completion. Pipe the output into your shell::
|
|
7
|
+
|
|
8
|
+
eval "$(python autocomp.py)"
|
|
9
|
+
|
|
10
|
+
Or add the printed command directly to your shell's rc file (``.zshrc``,
|
|
11
|
+
``.bashrc``, ``config.fish``, or ``$PROFILE`` on PowerShell).
|
|
12
|
+
|
|
13
|
+
You can also bypass autodetection by passing an explicit shell name::
|
|
14
|
+
|
|
15
|
+
python autocomp.py --shell fish
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import os
|
|
22
|
+
import platform
|
|
23
|
+
import shutil
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
COMMAND_NAME = "zhihu"
|
|
27
|
+
|
|
28
|
+
# Shells that Click natively supports for completion.
|
|
29
|
+
_SUPPORTED_SHELLS = frozenset({"bash", "zsh", "fish", "powershell"})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def detect_shell() -> str | None:
|
|
33
|
+
"""Best-effort detection of the active shell.
|
|
34
|
+
|
|
35
|
+
Returns one of ``"zsh"``, ``"bash"``, ``"fish"``, ``"powershell"``, or *None*.
|
|
36
|
+
"""
|
|
37
|
+
system = platform.system()
|
|
38
|
+
|
|
39
|
+
# ── Windows ──────────────────────────────────────────────────────
|
|
40
|
+
if system == "Windows":
|
|
41
|
+
# PSModulePath is the most reliable PowerShell-only env var.
|
|
42
|
+
if "PSModulePath" in os.environ:
|
|
43
|
+
return "powershell"
|
|
44
|
+
# Fallback: check COMSPEC or SHELL for pwsh mentions.
|
|
45
|
+
shell = os.environ.get("SHELL", "") or os.environ.get("COMSPEC", "")
|
|
46
|
+
if "powershell" in shell.lower() or "pwsh" in shell.lower():
|
|
47
|
+
return "powershell"
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
# ── Linux / macOS ────────────────────────────────────────────────
|
|
51
|
+
if system in ("Linux", "Darwin"):
|
|
52
|
+
# $SHELL is the login shell — accurate enough for the vast
|
|
53
|
+
# majority of users.
|
|
54
|
+
shell_path = os.environ.get("SHELL", "")
|
|
55
|
+
basename = os.path.basename(shell_path)
|
|
56
|
+
if basename in ("zsh", "bash", "fish"):
|
|
57
|
+
return basename
|
|
58
|
+
# Some distros symlink /bin/sh → bash; be tolerant.
|
|
59
|
+
if basename == "sh":
|
|
60
|
+
if os.environ.get("BASH_VERSION"):
|
|
61
|
+
return "bash"
|
|
62
|
+
if os.environ.get("ZSH_VERSION"):
|
|
63
|
+
return "zsh"
|
|
64
|
+
# Fish sets FISH_VERSION even when $SHELL doesn't point to it
|
|
65
|
+
# (e.g. launched as a subshell from another shell).
|
|
66
|
+
if os.environ.get("FISH_VERSION"):
|
|
67
|
+
return "fish"
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _detect_with_fallback(override: str | None) -> str:
|
|
74
|
+
"""Resolve the shell name, preferring *override* when given.
|
|
75
|
+
|
|
76
|
+
:param override: Explicit shell name from ``--shell``, or *None*.
|
|
77
|
+
:returns: A shell name in ``_SUPPORTED_SHELLS``.
|
|
78
|
+
:raises SystemExit: When detection fails or the shell is unsupported.
|
|
79
|
+
"""
|
|
80
|
+
if override is not None:
|
|
81
|
+
override = override.lower()
|
|
82
|
+
if override not in _SUPPORTED_SHELLS:
|
|
83
|
+
supported = ", ".join(sorted(_SUPPORTED_SHELLS))
|
|
84
|
+
sys.exit(f"Unsupported shell: {override!r}. Supported shells: {supported}.")
|
|
85
|
+
return override
|
|
86
|
+
|
|
87
|
+
shell = detect_shell()
|
|
88
|
+
if shell is not None:
|
|
89
|
+
return shell
|
|
90
|
+
|
|
91
|
+
system = platform.system()
|
|
92
|
+
shell_env = os.environ.get("SHELL", "?")
|
|
93
|
+
supported = ", ".join(sorted(_SUPPORTED_SHELLS))
|
|
94
|
+
msg = (
|
|
95
|
+
f"Unsupported environment: OS={system}, SHELL={shell_env}. "
|
|
96
|
+
f"Supported shells: {supported}. Use --shell to pick one explicitly."
|
|
97
|
+
)
|
|
98
|
+
sys.exit(msg)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_completion_command(shell: str) -> str:
|
|
102
|
+
"""Return the eval-ready autocompletion command for *shell*.
|
|
103
|
+
|
|
104
|
+
:param shell: One of ``"bash"``, ``"zsh"``, ``"fish"``, ``"powershell"``.
|
|
105
|
+
"""
|
|
106
|
+
if shutil.which(COMMAND_NAME) is None:
|
|
107
|
+
install_path = os.path.abspath(os.path.dirname(__file__))
|
|
108
|
+
sys.exit(f"{COMMAND_NAME} command not found. Please install it first: `pip install -e {install_path}`")
|
|
109
|
+
|
|
110
|
+
env_var = f"_{COMMAND_NAME.upper()}_COMPLETE"
|
|
111
|
+
|
|
112
|
+
if shell == "zsh":
|
|
113
|
+
return f'eval "$({env_var}=zsh_source {COMMAND_NAME})"'
|
|
114
|
+
if shell == "bash":
|
|
115
|
+
return f'eval "$({env_var}=bash_source {COMMAND_NAME})"'
|
|
116
|
+
if shell == "fish":
|
|
117
|
+
return f"{env_var}=fish_source {COMMAND_NAME} | source"
|
|
118
|
+
if shell == "powershell":
|
|
119
|
+
return f"& $env:{env_var}=powershell_source {COMMAND_NAME} | Out-String | Invoke-Expression"
|
|
120
|
+
|
|
121
|
+
sys.exit(f"Unsupported shell: {shell}")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def main() -> None:
|
|
125
|
+
parser = argparse.ArgumentParser(
|
|
126
|
+
description=f"Print the eval-ready shell completion command for {COMMAND_NAME}.",
|
|
127
|
+
)
|
|
128
|
+
_ = parser.add_argument(
|
|
129
|
+
"-s",
|
|
130
|
+
"--shell",
|
|
131
|
+
choices=sorted(_SUPPORTED_SHELLS),
|
|
132
|
+
default=None,
|
|
133
|
+
help="Shell to generate completion for (auto-detected when omitted).",
|
|
134
|
+
)
|
|
135
|
+
args = parser.parse_args()
|
|
136
|
+
|
|
137
|
+
shell = _detect_with_fallback(args.shell)
|
|
138
|
+
print(get_completion_command(shell))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
main()
|