kuaishou · v1.0 · 2026-07-26 · sha256 e670a7753bf7e4aa

kuaishou v1.0A

Immutable. This exact content is served forever at /api/v1/blob/e670a7753bf7e4aa.

---
name: kuaishou
description: Publish video to the user's own 快手 (Kuaishou) account and read their works via the Kuaishou open platform. Use when the user mentions 快手, Kuaishou, 发快手, 发布到快手, 我的快手作品, or wants to post a generated video to their Kuaishou account.
when_to_use: |
  Trigger for anything on the user's own 快手 account through the official
  open platform: publishing a video (e.g. one generated by the video
  skills), listing their works with play/like/comment counts, inspecting
  one work, or checking their account. Publishing is a real, immediately
  public post — always confirm the caption AND that the video is the
  user's own original work before running with --confirm.
connections: [kuaishou]
allowed_tools: [Bash]
license: Apache-2.0
metadata:
  author: acedatacloud
  version: "1.0"
---

All calls go through `scripts/kuaishou.py` (stdlib-only). The user's OAuth token
arrives as `$KUAISHOU_TOKEN` and the app id as `$KUAISHOU_APP_ID` (injected from
the connector's `metadata.platform_env`); the script reads both and fails fast
with a clear message if either is missing — never print either.

Resolve the script first (`$SKILL_DIR` may point at a different skill loaded the
same turn), and repeat this preamble in every Bash block:

```bash
KS="$SKILL_DIR/scripts/kuaishou.py"; [ -f "$KS" ] || KS=$(find /tmp -maxdepth 8 -path '*/skills/*/scripts/kuaishou.py' 2>/dev/null | head -1)
[ -f "$KS" ] || { echo "kuaishou script not found (SKILL_DIR=$SKILL_DIR)" >&2; exit 1; }
```

## Read

```bash
python3 "$KS" whoami                  # nickname, avatar, fans, follows, city
python3 "$KS" works --limit 20        # works + play/like/comment counts
python3 "$KS" works --limit 20 --cursor <photo_id>   # next page
python3 "$KS" work <photo-id>         # one work
python3 "$KS" counts                  # public / friend / private / total
```

## Publish a video

**This posts publicly to the user's real account — there is no draft mode.**
Before publishing, confirm with the user in chat:

1. the caption (required by 快手), and
2. that the video is **their own original work** — 快手 bans accounts that
   publish non-original video, and the ban lands on *the user's* account.

Without a trailing `--confirm` the command only dry-runs and publishes nothing.
`--confirm` must be the **last** argument.

```bash
# 1) Dry run — show the user exactly what will be posted
python3 "$KS" publish --caption "标题" --video-url "https://cdn.acedata.cloud/....mp4" \
  --cover-url "https://cdn.acedata.cloud/....jpg"

# 2) After they confirm in chat
python3 "$KS" publish --caption "标题" --video-url "https://cdn.acedata.cloud/....mp4" \
  --cover-url "https://cdn.acedata.cloud/....jpg" --confirm
```

A cover image is **required** (`--cover-url` or `--cover-file`, < 10MB). Local
files work too via `--video-file` / `--cover-file`. Optional: `--stereo-type`
for 360/180 panoramic video, `--product-id` to attach a 小黄车 product.

Remote `--*-url` inputs must live on **`cdn.acedata.cloud`** (or Kuaishou's own
image hosts). Anything else is rejected — upload it to our CDN first, or pass a
local path. This blocks a hostile URL from turning the upload step into an SSRF.

After a successful publish, record the deliverable once (see
`_shared/artifacts.md`):

```
publish_artifact(kind="video", channel="kuaishou", title="<caption>",
                 url="<the url returned by the script>", status="delivered")
```

## Gotchas

- **Upload success ≠ playable video.** The upload step only confirms bytes
  arrived; a malformed file fails later at transcode with `视频发布失败`
  (120003) or `视频未上传成功` (120002). Report those verbatim.
- Rate limits: **1000 calls/day per user**, 100k/day per app. `100100402` means
  the limit was hit *or* the account is banned.
- `ACCESS_DENIED` = the authorization is missing that endpoint's scope →
  reconnect 快手 and grant it. Token expiry (`100200108`) also means reconnect.
- Kuaishou answers HTTP 200 even on failure — the script already checks
  `result != 1`, so trust its `error` field rather than the exit status alone.
- Connections need re-authorizing roughly every 180 days: the refresh token does
  not extend on refresh. If the user hits an auth error, have them reconnect.