小红书重构

1. 图文上传
2. 视频上传(封面,定时)
3. cli
4. skill
5. 无头模式
This commit is contained in:
home-dev-pookz
2026-03-25 15:19:40 +08:00
parent ce9a9f102e
commit 90d03dc15a
32 changed files with 1325 additions and 98 deletions
+184
View File
@@ -0,0 +1,184 @@
import asyncio
import tempfile
import unittest
from argparse import Namespace
from pathlib import Path
from unittest.mock import AsyncMock, patch
import sau_cli
class BrowserCliParserTests(unittest.TestCase):
def test_build_parser_accepts_xiaohongshu_login(self):
parser = sau_cli.build_parser()
args = parser.parse_args(["xiaohongshu", "login", "--account", "creator"])
self.assertEqual(args.platform, "xiaohongshu")
self.assertEqual(args.action, "login")
def test_douyin_upload_video_accepts_desc(self):
with tempfile.TemporaryDirectory() as tmp_dir:
video_path = Path(tmp_dir) / "demo.mp4"
video_path.write_bytes(b"video")
parser = sau_cli.build_parser()
args = parser.parse_args(
[
"douyin",
"upload-video",
"--account",
"creator",
"--file",
str(video_path),
"--title",
"标题",
"--desc",
"视频简介",
]
)
self.assertEqual(args.desc, "视频简介")
def test_kuaishou_upload_note_accepts_title_and_note(self):
with tempfile.TemporaryDirectory() as tmp_dir:
image_path = Path(tmp_dir) / "1.png"
image_path.write_bytes(b"image")
parser = sau_cli.build_parser()
args = parser.parse_args(
[
"kuaishou",
"upload-note",
"--account",
"creator",
"--images",
str(image_path),
"--title",
"图文标题",
"--note",
"图文正文",
]
)
self.assertEqual(args.title, "图文标题")
self.assertEqual(args.note, "图文正文")
def test_xiaohongshu_upload_video_defaults_to_headless(self):
with tempfile.TemporaryDirectory() as tmp_dir:
video_path = Path(tmp_dir) / "demo.mp4"
video_path.write_bytes(b"video")
parser = sau_cli.build_parser()
args = parser.parse_args(
[
"xiaohongshu",
"upload-video",
"--account",
"creator",
"--file",
str(video_path),
"--title",
"视频标题",
]
)
self.assertTrue(args.headless)
def test_xiaohongshu_upload_note_accepts_headed(self):
with tempfile.TemporaryDirectory() as tmp_dir:
image_path = Path(tmp_dir) / "1.png"
image_path.write_bytes(b"image")
parser = sau_cli.build_parser()
args = parser.parse_args(
[
"xiaohongshu",
"upload-note",
"--account",
"creator",
"--images",
str(image_path),
"--title",
"图文标题",
"--note",
"图文正文",
"--headed",
]
)
self.assertFalse(args.headless)
class BrowserCliDispatchTests(unittest.TestCase):
def test_dispatch_xiaohongshu_check_prints_valid(self):
args = Namespace(platform="xiaohongshu", action="check", account="creator")
with patch("sau_cli.check_xiaohongshu_account", new=AsyncMock(return_value=True)):
code = asyncio.run(sau_cli.dispatch(args))
self.assertEqual(code, 0)
def test_dispatch_douyin_upload_note_uses_new_request_fields(self):
args = Namespace(
platform="douyin",
action="upload-note",
account="creator",
images=[Path("1.png")],
title="图文标题",
note="图文正文",
tags="测试,图文",
schedule=0,
debug=False,
headless=True,
)
with patch("sau_cli.upload_note", new=AsyncMock()) as mock_upload:
asyncio.run(sau_cli.dispatch(args))
request = mock_upload.await_args.args[0]
self.assertEqual(request.title, "图文标题")
self.assertEqual(request.note, "图文正文")
def test_dispatch_xiaohongshu_upload_video_uses_headed_request(self):
args = Namespace(
platform="xiaohongshu",
action="upload-video",
account="creator",
file=Path("demo.mp4"),
title="视频标题",
desc="视频简介",
tags="测试,视频",
schedule=0,
thumbnail=None,
debug=False,
headless=False,
)
with patch("sau_cli.upload_xiaohongshu_video", new=AsyncMock()) as mock_upload:
asyncio.run(sau_cli.dispatch(args))
request = mock_upload.await_args.args[0]
self.assertEqual(request.title, "视频标题")
self.assertEqual(request.description, "视频简介")
self.assertFalse(request.headless)
def test_dispatch_xiaohongshu_upload_note_uses_headless_request(self):
args = Namespace(
platform="xiaohongshu",
action="upload-note",
account="creator",
images=[Path("1.png"), Path("2.png")],
title="图文标题",
note="图文正文",
tags="测试,图文",
schedule=0,
debug=False,
headless=True,
)
with patch("sau_cli.upload_xiaohongshu_note", new=AsyncMock()) as mock_upload:
asyncio.run(sau_cli.dispatch(args))
request = mock_upload.await_args.args[0]
self.assertEqual(request.title, "图文标题")
self.assertEqual(request.note, "图文正文")
self.assertTrue(request.headless)
self.assertEqual(len(request.image_files), 2)
if __name__ == "__main__":
unittest.main()