opp-radar 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 程序员白大力
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,89 @@
1
+ Metadata-Version: 2.4
2
+ Name: opp-radar
3
+ Version: 0.1.0
4
+ Summary: Opportunity radar for indie devs: render a WeChat-style article from Markdown and push it to your Official Account draft box.
5
+ Author: 程序员白大力
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/baiyigali/opp_radar
8
+ Project-URL: Repository, https://github.com/baiyigali/opp_radar
9
+ Keywords: wechat,wechat-mp,公众号,markdown,wechat-formatter,publish,indie-dev,opportunity
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Office/Business
19
+ Classifier: Topic :: Text Processing :: Markup
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: wechat-formatter
24
+ Requires-Dist: wechat-publish
25
+ Dynamic: license-file
26
+
27
+ # opp-radar
28
+
29
+ 面向个人开发者 / 技术创业者的"机会雷达":从公开技术信号里筛出小团队能做的中小产品机会,自动写成公众号专栏,渲染排版后推到草稿箱(发表由人工在后台完成)。
30
+
31
+ 专栏名:**开发者机会观察**(公众号:程序员白大力)。觉得有用欢迎关注。
32
+
33
+ ## 目录结构
34
+
35
+ ```
36
+ opp-radar/
37
+ opp_radar/ # 安装后的 Python 包(render / publish / cli)
38
+ render.py · publish.py · cli.py · __init__.py · py.typed
39
+ prompts/
40
+ dev.md # 开发者机会观察(dev 领域)完整提示词
41
+ # 以后加 marketing.md、xxx.md 等其他领域,复用 opp_radar/
42
+ scripts/
43
+ render.py # 薄壳:转发到 opp_radar render(兼容旧调用,无需安装)
44
+ publish.py # 薄壳:转发到 opp_radar publish
45
+ examples/
46
+ 开发者机会观察-第5期.md/.png/.html # 一篇成稿样例
47
+ tests/ # 冒烟测试
48
+ .github/workflows/publish.yml # CI:构建 + TestPyPI/PyPI(OIDC 免密)
49
+ pyproject.toml # 打包配置,提供 `opp-radar` 命令
50
+ issues/ # 各期产出,gitignore,只在本地(用于去重)
51
+ config.json # 微信凭据,gitignore,不进版本库
52
+ ```
53
+
54
+ ## 跑一期
55
+
56
+ 安装(开发模式):
57
+ ```bash
58
+ pip install -e .
59
+ ```
60
+ 然后:
61
+ 1. 按 `prompts/dev.md` 的流程:找信号 → 反向验证 → 写 `.md` → 出 `.png`(都落在 `issues/`);
62
+ 2. 渲染:`opp-radar render "开发者机会观察-第N期"`;
63
+ 3. 推草稿:`opp-radar publish "开发者机会观察-第N期" "<标题>" "<摘要>"`,再去公众号后台草稿箱点"发表"。
64
+
65
+ > 不想安装时也可直接用薄壳脚本,效果一样:
66
+ > `python3 scripts/render.py "..."` / `python3 scripts/publish.py "..."`。
67
+
68
+ ## 样例
69
+
70
+ 看 `examples/开发者机会观察-第5期.html` 可直接在浏览器打开预览最终排版效果(科技风、经典蓝 #2563eb)。
71
+
72
+ ## 依赖
73
+
74
+ ```bash
75
+ pip install -e .
76
+ # 或手动:pip install wechat-formatter wechat-publish
77
+ ```
78
+
79
+ ## 本地凭据
80
+
81
+ 根目录 `config.json`:
82
+ ```json
83
+ { "appid": "...", "secret": "...", "author": "..." }
84
+ ```
85
+ 该文件已在 `.gitignore` 中,**不要提交到公开仓库**。
86
+
87
+ ## 铁律
88
+
89
+ 推草稿脚本只执行一次,无论返回成功/报错/超时都绝不重试,避免重复建草稿。
@@ -0,0 +1,63 @@
1
+ # opp-radar
2
+
3
+ 面向个人开发者 / 技术创业者的"机会雷达":从公开技术信号里筛出小团队能做的中小产品机会,自动写成公众号专栏,渲染排版后推到草稿箱(发表由人工在后台完成)。
4
+
5
+ 专栏名:**开发者机会观察**(公众号:程序员白大力)。觉得有用欢迎关注。
6
+
7
+ ## 目录结构
8
+
9
+ ```
10
+ opp-radar/
11
+ opp_radar/ # 安装后的 Python 包(render / publish / cli)
12
+ render.py · publish.py · cli.py · __init__.py · py.typed
13
+ prompts/
14
+ dev.md # 开发者机会观察(dev 领域)完整提示词
15
+ # 以后加 marketing.md、xxx.md 等其他领域,复用 opp_radar/
16
+ scripts/
17
+ render.py # 薄壳:转发到 opp_radar render(兼容旧调用,无需安装)
18
+ publish.py # 薄壳:转发到 opp_radar publish
19
+ examples/
20
+ 开发者机会观察-第5期.md/.png/.html # 一篇成稿样例
21
+ tests/ # 冒烟测试
22
+ .github/workflows/publish.yml # CI:构建 + TestPyPI/PyPI(OIDC 免密)
23
+ pyproject.toml # 打包配置,提供 `opp-radar` 命令
24
+ issues/ # 各期产出,gitignore,只在本地(用于去重)
25
+ config.json # 微信凭据,gitignore,不进版本库
26
+ ```
27
+
28
+ ## 跑一期
29
+
30
+ 安装(开发模式):
31
+ ```bash
32
+ pip install -e .
33
+ ```
34
+ 然后:
35
+ 1. 按 `prompts/dev.md` 的流程:找信号 → 反向验证 → 写 `.md` → 出 `.png`(都落在 `issues/`);
36
+ 2. 渲染:`opp-radar render "开发者机会观察-第N期"`;
37
+ 3. 推草稿:`opp-radar publish "开发者机会观察-第N期" "<标题>" "<摘要>"`,再去公众号后台草稿箱点"发表"。
38
+
39
+ > 不想安装时也可直接用薄壳脚本,效果一样:
40
+ > `python3 scripts/render.py "..."` / `python3 scripts/publish.py "..."`。
41
+
42
+ ## 样例
43
+
44
+ 看 `examples/开发者机会观察-第5期.html` 可直接在浏览器打开预览最终排版效果(科技风、经典蓝 #2563eb)。
45
+
46
+ ## 依赖
47
+
48
+ ```bash
49
+ pip install -e .
50
+ # 或手动:pip install wechat-formatter wechat-publish
51
+ ```
52
+
53
+ ## 本地凭据
54
+
55
+ 根目录 `config.json`:
56
+ ```json
57
+ { "appid": "...", "secret": "...", "author": "..." }
58
+ ```
59
+ 该文件已在 `.gitignore` 中,**不要提交到公开仓库**。
60
+
61
+ ## 铁律
62
+
63
+ 推草稿脚本只执行一次,无论返回成功/报错/超时都绝不重试,避免重复建草稿。
@@ -0,0 +1,3 @@
1
+ """opp_radar:开发者机会观察自动出稿流水线的渲染与推送工具。"""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,44 @@
1
+ """opp-radar 命令行入口。
2
+
3
+ 安装后提供两个子命令:
4
+ opp-radar render "<主名>" # issues/<主名>.md -> .html
5
+ opp-radar publish "<主名>" "<标题>" "<摘要>" # 推到公众号草稿箱
6
+ 两者都在当前工作目录下读写 issues/ 与 config.json。
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import sys
12
+
13
+
14
+ def main() -> int:
15
+ parser = argparse.ArgumentParser(
16
+ prog="opp-radar",
17
+ description="开发者机会观察:渲染公众号 HTML 并推草稿箱。",
18
+ )
19
+ sub = parser.add_subparsers(dest="cmd", required=True)
20
+
21
+ pr = sub.add_parser("render", help="把 issues/<主名>.md 渲染成公众号 HTML")
22
+ pr.add_argument("base", help="文件名主名,如 开发者机会观察-第6期")
23
+
24
+ pp = sub.add_parser("publish", help="把 issues/<主名>.html+.png 推到公众号草稿箱")
25
+ pp.add_argument("base", help="文件名主名")
26
+ pp.add_argument("title", help="文章标题")
27
+ pp.add_argument("digest", help="摘要(120 字内)")
28
+
29
+ args = parser.parse_args()
30
+
31
+ if args.cmd == "render":
32
+ from .render import render
33
+ render(args.base)
34
+ return 0
35
+ if args.cmd == "publish":
36
+ from .publish import push_draft
37
+ push_draft(args.base, args.title, args.digest)
38
+ return 0
39
+ parser.error("未知子命令")
40
+ return 2
41
+
42
+
43
+ if __name__ == "__main__":
44
+ raise SystemExit(main())
@@ -0,0 +1,40 @@
1
+ """把本期 HTML + 封面推到微信公众号草稿箱(只存草稿,不群发)。"""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+
7
+ from wechat_publish import WeChatAPIError, push_articles
8
+
9
+
10
+ def push_draft(
11
+ base: str,
12
+ title: str,
13
+ digest: str,
14
+ config_path: str = "config.json",
15
+ issues_dir: str = "issues",
16
+ ) -> str | None:
17
+ """读 config.json 凭据,建草稿。无论成功/报错都只调用一次,绝不重试。"""
18
+ with open(config_path, "r", encoding="utf-8") as f:
19
+ cfg = json.load(f)
20
+
21
+ try:
22
+ media_id = push_articles(
23
+ appid=cfg["appid"],
24
+ secret=cfg["secret"],
25
+ articles=[{
26
+ "html_path": os.path.join(issues_dir, f"{base}.html"),
27
+ "title": title,
28
+ "cover_path": os.path.join(issues_dir, f"{base}.png"),
29
+ "digest": digest,
30
+ }],
31
+ author=cfg["author"],
32
+ open_comment=False,
33
+ publish_now=False, # 个人未认证号无 freepublish 发布权限,发表由人工完成
34
+ )
35
+ print("DRAFT_MEDIA_ID:", media_id)
36
+ return media_id
37
+ except WeChatAPIError as e:
38
+ # 常见 40164 = 出口 IP 未加白。无论什么错都不重试。
39
+ print("WECHAT_ERROR:", e)
40
+ return None
File without changes
@@ -0,0 +1,49 @@
1
+ """把 <主名>.md 用 wechat_formatter 渲染成公众号内联样式 HTML。"""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+
6
+ from wechat_formatter import FormatTweaks, get_template, render_article
7
+
8
+
9
+ def render(base: str, issues_dir: str = "issues") -> str:
10
+ """读取 issues_dir/<base>.md,写出 issues_dir/<base>.html,返回 html 路径。"""
11
+ md_path = os.path.join(issues_dir, f"{base}.md")
12
+ html_path = os.path.join(issues_dir, f"{base}.html")
13
+
14
+ with open(md_path, "r", encoding="utf-8") as f:
15
+ md = f.read()
16
+
17
+ template = get_template("科技风", "经典") # 科技风 + 经典蓝 #2563eb
18
+ tweaks = FormatTweaks(
19
+ fontSize=15,
20
+ lineHeight=1.8,
21
+ paragraphSpacing=18,
22
+ imageRadius=6,
23
+ )
24
+ body = render_article(md, template, tweaks)
25
+
26
+ html = f"""<!DOCTYPE html>
27
+ <html lang="zh-CN">
28
+ <head>
29
+ <meta charset="utf-8">
30
+ <meta name="viewport" content="width=device-width, initial-scale=1">
31
+ <title>{base}</title>
32
+ <style>
33
+ body {{ margin:0; background:#f2f3f5; padding:24px 0; }}
34
+ .wechat-article {{ max-width:677px; margin:0 auto; background:#fff;
35
+ padding:24px 16px; box-sizing:border-box; }}
36
+ </style>
37
+ </head>
38
+ <body>
39
+ <div class="wechat-article">
40
+ {body}
41
+ </div>
42
+ </body>
43
+ </html>"""
44
+
45
+ with open(html_path, "w", encoding="utf-8") as f:
46
+ f.write(html)
47
+
48
+ print("HTML_OK:", html_path)
49
+ return html_path
@@ -0,0 +1,89 @@
1
+ Metadata-Version: 2.4
2
+ Name: opp-radar
3
+ Version: 0.1.0
4
+ Summary: Opportunity radar for indie devs: render a WeChat-style article from Markdown and push it to your Official Account draft box.
5
+ Author: 程序员白大力
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/baiyigali/opp_radar
8
+ Project-URL: Repository, https://github.com/baiyigali/opp_radar
9
+ Keywords: wechat,wechat-mp,公众号,markdown,wechat-formatter,publish,indie-dev,opportunity
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Office/Business
19
+ Classifier: Topic :: Text Processing :: Markup
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: wechat-formatter
24
+ Requires-Dist: wechat-publish
25
+ Dynamic: license-file
26
+
27
+ # opp-radar
28
+
29
+ 面向个人开发者 / 技术创业者的"机会雷达":从公开技术信号里筛出小团队能做的中小产品机会,自动写成公众号专栏,渲染排版后推到草稿箱(发表由人工在后台完成)。
30
+
31
+ 专栏名:**开发者机会观察**(公众号:程序员白大力)。觉得有用欢迎关注。
32
+
33
+ ## 目录结构
34
+
35
+ ```
36
+ opp-radar/
37
+ opp_radar/ # 安装后的 Python 包(render / publish / cli)
38
+ render.py · publish.py · cli.py · __init__.py · py.typed
39
+ prompts/
40
+ dev.md # 开发者机会观察(dev 领域)完整提示词
41
+ # 以后加 marketing.md、xxx.md 等其他领域,复用 opp_radar/
42
+ scripts/
43
+ render.py # 薄壳:转发到 opp_radar render(兼容旧调用,无需安装)
44
+ publish.py # 薄壳:转发到 opp_radar publish
45
+ examples/
46
+ 开发者机会观察-第5期.md/.png/.html # 一篇成稿样例
47
+ tests/ # 冒烟测试
48
+ .github/workflows/publish.yml # CI:构建 + TestPyPI/PyPI(OIDC 免密)
49
+ pyproject.toml # 打包配置,提供 `opp-radar` 命令
50
+ issues/ # 各期产出,gitignore,只在本地(用于去重)
51
+ config.json # 微信凭据,gitignore,不进版本库
52
+ ```
53
+
54
+ ## 跑一期
55
+
56
+ 安装(开发模式):
57
+ ```bash
58
+ pip install -e .
59
+ ```
60
+ 然后:
61
+ 1. 按 `prompts/dev.md` 的流程:找信号 → 反向验证 → 写 `.md` → 出 `.png`(都落在 `issues/`);
62
+ 2. 渲染:`opp-radar render "开发者机会观察-第N期"`;
63
+ 3. 推草稿:`opp-radar publish "开发者机会观察-第N期" "<标题>" "<摘要>"`,再去公众号后台草稿箱点"发表"。
64
+
65
+ > 不想安装时也可直接用薄壳脚本,效果一样:
66
+ > `python3 scripts/render.py "..."` / `python3 scripts/publish.py "..."`。
67
+
68
+ ## 样例
69
+
70
+ 看 `examples/开发者机会观察-第5期.html` 可直接在浏览器打开预览最终排版效果(科技风、经典蓝 #2563eb)。
71
+
72
+ ## 依赖
73
+
74
+ ```bash
75
+ pip install -e .
76
+ # 或手动:pip install wechat-formatter wechat-publish
77
+ ```
78
+
79
+ ## 本地凭据
80
+
81
+ 根目录 `config.json`:
82
+ ```json
83
+ { "appid": "...", "secret": "...", "author": "..." }
84
+ ```
85
+ 该文件已在 `.gitignore` 中,**不要提交到公开仓库**。
86
+
87
+ ## 铁律
88
+
89
+ 推草稿脚本只执行一次,无论返回成功/报错/超时都绝不重试,避免重复建草稿。
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ opp_radar/__init__.py
5
+ opp_radar/cli.py
6
+ opp_radar/publish.py
7
+ opp_radar/py.typed
8
+ opp_radar/render.py
9
+ opp_radar.egg-info/PKG-INFO
10
+ opp_radar.egg-info/SOURCES.txt
11
+ opp_radar.egg-info/dependency_links.txt
12
+ opp_radar.egg-info/entry_points.txt
13
+ opp_radar.egg-info/requires.txt
14
+ opp_radar.egg-info/top_level.txt
15
+ tests/test_smoke.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ opp-radar = opp_radar.cli:main
@@ -0,0 +1,2 @@
1
+ wechat-formatter
2
+ wechat-publish
@@ -0,0 +1 @@
1
+ opp_radar
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "opp-radar"
7
+ version = "0.1.0"
8
+ description = "Opportunity radar for indie devs: render a WeChat-style article from Markdown and push it to your Official Account draft box."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "程序员白大力" },
14
+ ]
15
+ keywords = ["wechat", "wechat-mp", "公众号", "markdown", "wechat-formatter", "publish", "indie-dev", "opportunity"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Office/Business",
26
+ "Topic :: Text Processing :: Markup",
27
+ ]
28
+ dependencies = [
29
+ "wechat-formatter",
30
+ "wechat-publish",
31
+ ]
32
+
33
+ [project.scripts]
34
+ opp-radar = "opp_radar.cli:main"
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/baiyigali/opp_radar"
38
+ Repository = "https://github.com/baiyigali/opp_radar"
39
+
40
+ [tool.setuptools]
41
+ packages = ["opp_radar"]
42
+
43
+ [tool.setuptools.package-data]
44
+ opp_radar = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ def test_import_package():
2
+ import opp_radar
3
+ assert opp_radar.__version__
4
+
5
+
6
+ def test_cli_help():
7
+ from opp_radar.cli import main
8
+ import sys
9
+ argv = sys.argv
10
+ try:
11
+ sys.argv = ["opp-radar", "--help"]
12
+ try:
13
+ main()
14
+ except SystemExit as e:
15
+ assert e.code == 0
16
+ finally:
17
+ sys.argv = argv