Skip to content

feat: add video note publishing (post-video) - #2

Merged
murphykobe merged 1 commit into
mainfrom
feat/video-publishing
May 9, 2026
Merged

feat: add video note publishing (post-video)#2
murphykobe merged 1 commit into
mainfrom
feat/video-publishing

Conversation

@murphykobe

Copy link
Copy Markdown
Owner

Summary

  • Ports the post-video command from upstream jackwener/xiaohongshu-cli#15xhs post-video --title ... --body ... --video file.mp4 [--cover cover.jpg] [--topic ...] [--private].
  • Threads the per-request uploadAddr from the upload permit response through both image and video upload paths so video publishing also works under XHS_TARGET=rednote (rednote's permit endpoint returns a different upload host per request, which the upstream PR doesn't handle).
  • Bundles upstream's "Chinese-content fix": create_image_note and create_video_note now POST via _creator_post (the host the web client actually uses for note creation) and serialize business_binds with ensure_ascii=False.

Why threading uploadAddr matters here

Without it, the upstream PR works on xiaohongshu.com (where UPLOAD_HOST = ros-upload.xiaohongshu.com is a valid CDN endpoint) but breaks on rednote.com because the rednote permit response points uploads at a different host. Now both targets work without target-specific code paths in the upload methods.

Behavioral changes (existing functionality)

  • xhs post (image notes) now posts via the creator host (webapi.rednote.com / creator.xiaohongshu.com) rather than the edith host. Upstream verified this is the right host and that posting Chinese titles/bodies stops failing with the switch.
  • business_binds JSON is now serialized with ensure_ascii=False (no escaped Unicode in the embedded JSON string).

Refactor

Image and video note creation share a _post_note helper instead of two near-identical 30-line payload builders. Same payload shape as upstream — just deduped.

Test plan

  • uv run pytest tests/ — 114 passed, 27 skipped
  • XHS_TARGET=rednote uv run pytest tests/ — 114 passed, 27 skipped
  • ruff check xhs_cli/ clean
  • xhs post-video --help shows expected options
  • xhs post-video --video /missing.mp4 → "Video file not found"
  • xhs post-video --video foo.txt → "Unsupported video format '.txt'. Supported: .mov, .mp4"
  • Live publish on XHS_TARGET=rednote — pending. We have authenticated rednote sessions working from PR feat: support rednote.com via XHS_TARGET env var #1 but no live video upload was run. If the upload returns a 4xx, the most likely culprit is the uploadAddr host — easy to debug with XHS_VERBOSE=1.
  • Live publish on default xiaohongshu — pending; upstream confirmed it works for English content.

Files

  • xhs_cli/client_mixins.py — adds get_video_upload_permit, upload_video, create_video_note; folds create_image_note and create_video_note into _post_note; get_upload_permit returns uploadAddr; upload_file accepts upload_addr override.
  • xhs_cli/commands/creator.py — adds post_video command with validation; threads uploadAddr into the existing post command's image upload.
  • xhs_cli/cli.py — registers post-video.
  • xhs_cli/formatter_renderers.py — fixes a stale import-order lint carryover.
  • README.md — documents post-video in both English and Chinese sections.

Notes for reviewers

  • I deliberately skipped the upstream PR's PR_DESCRIPTION.md and test_video.mp4 files — both look like leftover scratch from the author's local repo, not source-of-truth.
  • I left out the upstream PR's commit [bundler-runtime…] test artifact for the same reason.

🤖 Generated with Claude Code

Ports the upstream `post-video` command from jackwener#15
and threads the per-request `uploadAddr` from the upload permit response
through both image and video upload paths so it works on rednote too.

Behavioral changes:
- New `xhs post-video` command (--video required; --cover optional;
  topics from --topic flags + body hashtags; --private supported).
- `create_image_note` now POSTs via `_creator_post`
  (`webapi.rednote.com` / `creator.xiaohongshu.com`) instead of the
  edith host. This matches the path the web client actually uses and
  is the upstream PR's fix for "Chinese title/body returns API error
  when posting." `business_binds` is now serialized with
  `ensure_ascii=False` for the same reason.
- `get_upload_permit` returns the `uploadAddr` field from the permit
  response. `upload_file` / `upload_video` accept an `upload_addr`
  override; falls back to the static `UPLOAD_HOST` constant when
  empty (preserves xiaohongshu behavior).

Refactor:
- Note creation paths share a single `_post_note` helper instead of
  two near-identical 30-line builders.

Test plan:
- `uv run pytest` — 114 passed under both XHS_TARGET=xiaohongshu
  (default) and XHS_TARGET=rednote.
- `ruff check` clean.
- `xhs post-video --help` and validation errors (missing file,
  unsupported extension) rendered correctly.
@murphykobe
murphykobe merged commit 07418f7 into main May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant