- 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
9.3 KiB
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):
GET https://scan.acfun.cn/rest/pc-direct/qr/start?type=WEB_LOGINreturns a base64 PNG plusqrLoginToken,qrLoginSignatureandexpireTime(120 s).scanResultis a single long-poll held by AcFun until the phone scans or the code expires. On scan it returns a rotated signature.acceptResultwith the rotated signature issues the session cookies; the plugin capturesSet-Cookie, persists the cookie through the Host credential service (acfun-sessiongrant 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.
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:
$env:ACFUN_COOKIE = 'auth_key=...; acPasstoken=...; _did=...'
Getting the cookie without the panel
- Sign in to https://www.acfun.cn/ in a desktop browser.
- Open DevTools → Network, reload any acfun.cn page, and copy the complete
Cookierequest header of the document request (it containsauth_key,acPasstoken,_did, and other session values). - Paste it as one line into
cookieorACFUN_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: trueand a cookie. With only one of them the tools returnWRITE_DISABLED/LOGIN_REQUIREDand 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 (
result400001–410999) is surfaced asCAPTCHA_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(includingsort: "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/pageSizeand always returns its first page (30 entries), soacfun_searchcannot paginate.sortis the only ordering control AcFun honours. - Bangumi (番剧) and article pages are not supported —
acfun_videoreportsUNSUPPORTED_RESOURCEinstead 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_danmakupasses it through ascursor/nextCursor. - Play URLs are time-limited signed m3u8 links; re-run
acfun_playurlwhen 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.