Files
dsh-acfun/README.md
T
tamakyi 97825f020d feat: QR login, AcFun settings panel, and 动态 (moment) tools
- scan.acfun.cn QR flow (start -> long-poll scanResult -> acceptResult) with
  rotated-signature handling, background poller, durable session in the Host
  credential service, and cookie handoff to the provider
- Client half: Settings -> AcFun page (status, QR code, poll, logout) over a
  same-origin /acfun-panel JSON API with cross-origin rejection
- acfun_moment / acfun_moment_comments / acfun_topic read tools, moment_like /
  moment_unlike / moment_banana actions, and comment posting on moments
- acfun_account status tool; docs for the QR contract, the 广场/动态 research
  verdict, and the client-composition restart requirement
2026-10-27 11:50:44 +08:00

185 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# dsh-plugin-acfun
DeepSeek Harness plugin for **AcFun (A站, acfun.cn)**: search videos, read video
metadata, comment threads, danmaku (弹幕), the day/week ranking, playable stream
URLs and 动态 (moments); interact with your own account (like, tip bananas,
favorite, follow, comment — including moments); and sign in by **scanning a QR
code in the Harness Web UI** (Settings → AcFun).
This is the AcFun counterpart of the community Bilibili tool plugins. Reads are
anonymous and work out of the box; every mutating call is gated behind
`allowWriteActions: true` **and** an AcFun login cookie, so installing the bundle
never silently gives the model write access to an account.
## Tools
| Tool | Kind | What it does |
| --- | --- | --- |
| `acfun_search` | read | Keyword video search; `sort: "views"` orders by play count (AcFun returns one fixed first page of up to 30). |
| `acfun_video` | read | Full metadata for one video: author, channel, tags, stats, publish time, cover. |
| `acfun_comments` | read | One page of a video's comment thread, in floor order. |
| `acfun_danmaku` | read | One batch of a video's 弹幕, ordered by in-video position, with cursor paging. |
| `acfun_rank` | read | Day or week ranking, all channels or one `channelId`. |
| `acfun_playurl` | read | m3u8 quality ladder (1080P+ / 1080P / 720P / 540P / 360P). |
| `acfun_moment` | read | One 动态 by id: text, topics, images, author, counts, canonical share URL. |
| `acfun_moment_comments` | read | One page of a 动态's comment thread (moments have their own comment enum). |
| `acfun_topic` | read | 社区圈 topic page (best effort, 15 newest items) — the only public way to discover current moment ids. |
| `acfun_interact` | write | Video: `like`, `unlike`, `banana`, `favorite`, `unfavorite`, `follow`, `unfollow`. Moment: `moment_like`, `moment_unlike`, `moment_banana`. |
| `acfun_post_comment` | write | Post a top-level comment or reply on a video (`acId`) or a 动态 (`momentId`). |
| `acfun_account` | read | Login state, credential source, whether interactions are enabled, and the next sign-in step. |
A model-facing skill (`skills/plugin-tool-acfun/SKILL.md`) teaches the tool
sequence, the write-safety rules, and the 动态 limitations.
## Install
Install the workspace directory as a profile bundle:
```
plugin_manager action=install_bundle target=C:\path\to\dsh-acfun
```
The bundle inserts two Loader rows: `acfun` (the tools, panel API and QR login)
and `acfun-skill-filesystem` (which exposes this package's `skills/` directory
to the agent). A local directory is linked, so edits to the plugin need a
Harness restart to load a fresh module generation.
To remove it, use `plugin_manager action=remove_bundle target=dsh-plugin-acfun`.
## QR login and the Web UI panel
The bundle ships a Client half (`client.js`) that adds a **Settings → AcFun**
page. It shows the current login state, the credential source and whether
interaction tools are enabled, renders the QR code, and polls until the phone
confirms.
Flow (all Host-side, `lib/qr-flow.js`):
1. `GET https://scan.acfun.cn/rest/pc-direct/qr/start?type=WEB_LOGIN` returns a
base64 PNG plus `qrLoginToken`, `qrLoginSignature` and `expireTime` (120 s).
2. `scanResult` is a single long-poll held by AcFun until the phone scans or the
code expires. On scan it returns a **rotated signature**.
3. `acceptResult` with the rotated signature issues the session cookies; the
plugin captures `Set-Cookie`, persists the cookie through the Host credential
service (`acfun-session` grant record), and points the provider at it.
The panel talks to the Host over `/acfun-panel/*` (same-origin JSON, cross-origin
requests rejected). Scanning a QR code is the only step a plugin cannot verify
by itself, so the confirm branch is exercised only by a real phone scan.
**Restart requirement:** a Client half added to a package that the Host already
scanned needs one Harness restart, then a page reload, before
**Settings → AcFun** appears. The graph is composed from the live Loader entry
set at boot, so a bundle installed into a running page is not in it yet. Detect
it with `GET /acfun-panel/state` (`client.path` must be non-null) or
`GET /acfun-panel/diagnose`; details and evidence are in
[`docs/client-panel.md`](docs/client-panel.md).
## Configuration
The row config lives in `cordis.patch.yml`; every key is optional.
| Key | Default | Meaning |
| --- | --- | --- |
| `cookie` | `''` | Full AcFun `Cookie` header value. Prefer the environment variable so the secret does not enter the patch. |
| `cookieEnv` | `ACFUN_COOKIE` | Environment variable read when `cookie` is empty. |
| `allowWriteActions` | `false` | Master switch for `acfun_interact` and `acfun_post_comment`. |
| `requestTimeoutMs` | `30000` | Per-HTTP-request timeout. |
| `timeoutMs` | `45000` | Cooperative per-tool-call budget (write calls use at least 60 s). |
A cookie from the panel's QR login is stored as a credential record and wins
over `cookie`/`ACFUN_COOKIE`; signing out in the panel falls back to the config.
Example with the environment variable:
```powershell
$env:ACFUN_COOKIE = 'auth_key=...; acPasstoken=...; _did=...'
```
### Getting the cookie without the panel
1. Sign in to <https://www.acfun.cn/> in a desktop browser.
2. Open DevTools → Network, reload any acfun.cn page, and copy the complete
`Cookie` request header of the document request (it contains `auth_key`,
`acPasstoken`, `_did`, and other session values).
3. Paste it as one line into `cookie` or `ACFUN_COOKIE`.
Treat that string like a password: it grants full access to the account. The
plugin never logs it.
## Safety model
- Reads cannot mutate anything and need no cookie.
- Writes require both `allowWriteActions: true` and a cookie. With only one of
them the tools return `WRITE_DISABLED` / `LOGIN_REQUIRED` and perform no HTTP
write request.
- Write tools are declared non-concurrency-safe so the harness will not run two
account mutations in parallel.
- A CAPTCHA/identity-verification challenge from AcFun (`result` 400001–410999)
is surfaced as `CAPTCHA_REQUIRED`; the plugin never tries to solve it.
## Verification status
Verified live on 2026-10-27 against acfun.cn (anonymous):
- All six read tools — `acfun_search` (including `sort: "views"`), `acfun_video`,
`acfun_comments`, `acfun_danmaku`, `acfun_rank`, `acfun_playurl`,
`acfun_moment`, `acfun_moment_comments`, `acfun_topic` — return real API data
and pass output-schema validation plus rendering
(`node scripts/live-check.mjs`).
- QR login issuance and the waiting/abort path were verified live against
`scan.acfun.cn` (a real ticket and PNG are returned; an unscanned ticket holds
the long-poll until the 120 s expiry, then reports "expired").
- All twelve tools register through a mock Cordis context, the panel routes are
served on a local HTTP server, and the write guard fails closed
(`node scripts/self-check.mjs`).
- Write routes exist and reject anonymous requests with `{"result":-401}`. The
authenticated happy path — including the final QR accept step and moment
writes — was **not** exercised here because no AcFun account was available.
Treat first use as a live test: check the result in the AcFun UI instead of
retrying blindly.
## Known limitations
- AcFun's pc-direct search endpoint ignores `page`/`pageSize` and always returns
its first page (30 entries), so `acfun_search` cannot paginate. `sort` is the
only ordering control AcFun honours.
- Bangumi (番剧) and article pages are not supported — `acfun_video` reports
`UNSUPPORTED_RESOURCE` instead of guessing.
- **No 广场 feed API exists.** After ~560 path probes no public square/recommend
moment list was found on any host; moment ids can only be discovered through
`acfun_topic` (server-rendered, 15 newest items, no pagination) or a share
link. The only moment *lists* are login-scoped following feeds.
- Publishing, deleting, reposting and voting on a 动态 are app-only behind the
signed midground token; the web plugin cannot do them.
- Moment like/banana/comment contracts are derived from the site's own store and
verified only up to their auth error (`401`), so treat moment writes as
experimental.
- Danmaku paging beyond the first batch depends on AcFun's opaque `pcursor`;
`acfun_danmaku` passes it through as `cursor`/`nextCursor`.
- Play URLs are time-limited signed m3u8 links; re-run `acfun_playurl` when one
expires. Downloading/merging streams is out of scope.
- This plugin only talks to acfun.cn's public web endpoints; it is unofficial and
can break when AcFun changes them.
## Development
```
node scripts/self-check.mjs # offline: exports, tool schemas, QR state machine, panel HTTP
node scripts/live-check.mjs # online: real reads, QR issuance, schema validation + render
```
No build step, no runtime dependencies. Everything under `lib/` and `client.js`
is plain ESM/JavaScript that imports only Node built-ins/globals. The bundle
intentionally exports no `Config` schema: a workspace-linked bundle cannot
resolve `@deepseek-ai/*` packages, so `lib/config.js` validates the row config
and falls back to defaults with warnings instead of using schemastery.
Endpoint notes: `docs/acfun-api.md` (videos/comments/danmaku/rank),
`docs/acfun-login.md` (QR login), `docs/acfun-moment.md` (广场/动态 research and
verdict).
## License
MIT — see `LICENSE`.