Files
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

9.3 KiB
Raw Permalink Blame History

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.

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=...'
  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.