Angiin

feat: 屏蔽权限弹窗 + 保存草稿命令

- cdp.py: new_page 中通过 Browser.setPermission 自动拒绝位置、通知、摄像头等权限弹窗
- publish.py: 新增 save_as_draft() 离开发布页触发自动保存
- cli.py: 新增 save-draft 子命令,用户取消发布时保存草稿
... ... @@ -420,6 +420,19 @@ def cmd_click_publish(args: argparse.Namespace) -> None:
browser.close()
def cmd_save_draft(args: argparse.Namespace) -> None:
"""保存为草稿(取消发布时调用)。"""
from xhs.publish import save_as_draft
browser, page = _connect_existing(args)
try:
save_as_draft(page)
_output({"success": True, "status": "内容已保存到草稿箱"})
finally:
browser.close_page(page)
browser.close()
def cmd_long_article(args: argparse.Namespace) -> None:
"""长文模式:填写内容 + 一键排版,返回模板列表。"""
from xhs.publish_long_article import publish_long_article
... ... @@ -677,6 +690,10 @@ def build_parser() -> argparse.ArgumentParser:
sub.add_argument("--content-file", required=True, help="描述内容文件路径")
sub.set_defaults(func=cmd_next_step)
# save-draft(保存草稿)
sub = subparsers.add_parser("save-draft", help="保存为草稿(取消发布时使用)")
sub.set_defaults(func=cmd_save_draft)
return parser
... ...
... ... @@ -572,6 +572,16 @@ class Browser:
},
)
# 拒绝权限弹窗(位置、通知等)
import contextlib
for perm in ("geolocation", "notifications", "midi", "camera", "microphone"):
with contextlib.suppress(CDPError):
self._cdp.send(
"Browser.setPermission",
{"permission": {"name": perm}, "setting": "denied"},
)
# 启用必要的 domain
page._send_session("Page.enable")
page._send_session("DOM.enable")
... ...
... ... @@ -121,6 +121,30 @@ def click_publish_button(page: Page) -> None:
logger.info("发布完成")
def save_as_draft(page: Page) -> None:
"""点击「暂存离开」按钮保存草稿。"""
clicked = page.evaluate(
"""
(() => {
const buttons = document.querySelectorAll('button.custom-button');
for (const btn of buttons) {
if (btn.textContent.trim() === '暂存离开') {
btn.click();
return true;
}
}
return false;
})()
"""
)
if clicked:
time.sleep(2)
logger.info("已点击「暂存离开」,内容已保存到草稿箱")
else:
logger.warning("未找到「暂存离开」按钮")
raise PublishError("未找到「暂存离开」按钮")
# ========== 页面导航 ==========
... ...