---
name: quark-pansou-collector
description: 'Search PanSou for Quark cloud-drive share candidates, apply deterministic policy filtering and link/title verification, then return one best Quark share link or, when explicitly requested, save the verified link into Quark drive with quarkpan.'
metadata:
  icon: ':lucide:folder-down:'
  title: Quark PanSou Collector
  packageName: '@zjxuyunshi/quark-pansou-collector'
  version: 0.0.2
---

# Quark PanSou Collector

## When to Use

Use this skill when the user asks to search PanSou by keyword and return one
best Quark share link. Also use it when the user asks to save, collect, archive,
sync, or transfer that selected Quark share into Quark drive. The default save
folder is `/z-sync`, and the user may request another Quark drive folder.

By default, this skill only returns one verified candidate link plus a compact
verification summary. It saves to `/z-sync` only when the user explicitly asks
to save/sync/collect/archive/transfer the result and does not name another
destination folder. If the user says where to save, pass that folder with
`--save-folder`. After a strong verified `selected` result is returned without
`--save`, ask the user whether to save it; tell them to reply `1` to save to
the shown folder. A reply of exactly `1` in that context is an explicit save
request for the last selected result.

Before any strong verification or save operation, rely on the helper's Quark
environment check. It uses `QUARK_CONFIG_DIR` when already set; otherwise it
defaults to `~/quarkpan-config` on the current computer. It installs `quarkpan`
with `python3 -m pip install --user quarkpan` if the CLI is missing, and checks
the login state. When saving is requested and login is missing, the helper
generates a QR code PNG in that config directory and waits for the user to scan
it. In Codex chat, show that local PNG with Markdown image syntax so the user
can scan it; interactive terminal QR output may be invisible to the user. In
Telegram or other gateway chats that support native media, send the PNG as a
native attachment using `MEDIA:<qr_code_path>` rather than only printing the
local path. Prefer starting the login/check command as a tracked background
process, record the start time, wait until `qr_code_path` exists with an mtime
newer than that start time, send the image immediately, and then continue
polling or ask the user to confirm after scanning; otherwise the short QR expiry
window may pass before the user can see it. If a previous login attempt timed
out, delete or ignore the stale `quark-login-qr.png` before sending a new QR;
never send a QR file merely because it exists.

The agent is not the content adjudicator. It must run the deterministic policy
filter first, then output only a candidate marked `transferable`. The agent may
explain policy results and ask for missing inputs, but it must not override the
policy gate or use subjective judgment to turn a blocked candidate into an
output link. If the user explicitly requests account bypass, captcha bypass, or
unlawful access, stop.

AI involvement is limited to: parsing the user's keyword, reporting the selected
link and explaining tool errors. Search filtering, URL handling, source
allowlisting, risk labels, best-candidate selection, and link verification are
programmatic.

## Inputs

- Required before searching: `keyword`.
- Optional: PanSou endpoint, default `https://s.panhunt.com`.
- Optional: source mode, default `all`; accepted PanSou values are `all`,
  `tg`, and `plugin`.
- Optional: maximum candidates to show, default 10 and cap at 20 unless the
  user explicitly asks for more.
- Optional: `refresh`, default false.
- Optional: policy JSON path. Default to `references/policy.default.json`.
- Optional: save selected link into `/z-sync`, default false and enabled only
  when the user explicitly asks to save/sync/collect/archive/transfer.
- Optional: save folder, default `/z-sync`. If the user says "保存到 X" or
  otherwise names a destination folder, pass that Quark drive folder with
  `--save-folder`.
- Optional: content choice, used only after the helper returns
  `needs_user_selection: true`. Pass the user's selected option number with
  `--content-choice <index>` and rerun the same command.
- Optional: Quark config directory. Defaults to existing `QUARK_CONFIG_DIR`,
  then `~/quarkpan-config` on the current computer.
- Optional: `--check-quark-env` for checking/installing `quarkpan` and login
  status without searching.

## Execution

PanSou search is a public HTTP API call, not an oo package or connector. Prefer
the bundled deterministic helper over ad hoc `curl`/`jq`, because it returns
policy labels and redacts non-transferable URLs.

From the skill directory, run:

```bash
python3 scripts/pansou_collect.py \
  --keyword "<keyword>" \
  --endpoint "https://s.panhunt.com" \
  --src all \
  --limit 10 \
  --policy references/policy.default.json \
  --one \
  --verify-link
```

The helper automatically sets `QUARK_CONFIG_DIR` from `--quark-config-dir`,
then any existing `QUARK_CONFIG_DIR`, then `~/quarkpan-config`. To check the
environment only, run:

```bash
python3 scripts/pansou_collect.py --check-quark-env --login-if-needed
```

If the JSON output contains `event: quark_login_required` with
`qr_code_path`, display that PNG in the chat for scanning. After the user scans
and confirms login in the Quark app, the helper continues until login succeeds
or times out.

When the user explicitly asks to save/sync/collect/archive/transfer the selected
result into Quark, add `--save`:

```bash
python3 scripts/pansou_collect.py \
  --keyword "<keyword>" \
  --endpoint "https://s.panhunt.com" \
  --src all \
  --limit 10 \
  --policy references/policy.default.json \
  --one \
  --verify-link \
  --save
```

The default save path is `/z-sync`. After selecting a `transferable`
candidate with successful strong content verification, the helper resolves or
creates the target Quark drive folder, obtains its real folder id, and saves the
share with `quark_client` using that folder id. This avoids the ambiguous
`quarkpan save -f` behavior where a missing destination folder can leave items
in the root. If the user explicitly requests another Quark drive folder, pass it
with `--save-folder`. Do not run `quarkpan` manually unless the helper is
unavailable and you have already reproduced the same selection, verification,
and target-folder rules.

If the user's `quarkpan` login uses a different config directory, pass it
explicitly:

```bash
python3 scripts/pansou_collect.py \
  --keyword "<keyword>" \
  --one \
  --verify-link \
  --quark-config-dir "/path/to/quarkpan/config"
```

The helper searches only Quark links, deduplicates by cleaned share URL, checks
title relevance, applies source/pattern policy, and returns JSON candidates with
`status`, `risk`, `reasons`, and `link_verification`. Link verification first
tries the logged-in `quark_client` share-detail API; this can detect expired or
unavailable shares and count files. If `quarkpan` is not logged in for the
current working directory/config, it falls back to a weak HTTP page check and
marks `weak_verification: true`.

In `--one` mode it returns only `selected`, using this rule: one
`transferable` candidate with successful strong content verification after
content disambiguation. Weak HTTP page checks are never enough for `--one`,
because expired Quark shares may still return HTTP 200.

Before selecting one result, the helper groups transferable candidates by
programmatic content variants. Seasons/parts,全集/合集/完整版 markers,
explicit year versions such as `2008 版本` and `2016 版`, and obvious
same-title editions such as subtitles after `：` are treated as different
content variants. If more than one strongly verified variant exists, the helper
returns `needs_user_selection: true` plus `selection_options`; do not output a
link or save anything yet. Ask the user which option number they want, then
rerun the same command with `--content-choice <index>`.

Do not ask the user when the remaining difference is only quality/encoding, for
example `720p`, `1080p`, `4K`, `2160p`, `蓝光`, `WEB-DL`, `HDR`, `DV`, or
`H.265`. Within a single content variant, the helper automatically selects the
highest-quality strongly verified candidate.

In `--save` mode it still uses the same `--one` selection rule before saving.
If there is no strongly verified selected link, stop without saving.

If the helper is unavailable, this is the raw PanSou request shape:

```bash
curl -sS -X POST 'https://s.panhunt.com/api/search' \
  -H 'Content-Type: application/json' \
  --data '{"kw":"<keyword>","cloud_types":["quark"],"res":"merge","src":"all"}'
```

Use `--data @payload.json` instead of inline JSON when values contain quotes,
newlines, or user-provided structured options. A minimal payload is:

```json
{
  "kw": "<keyword>",
  "cloud_types": ["quark"],
  "res": "merge",
  "src": "all"
}
```

If the user asks to force a fresh lookup, add `"refresh": true`. For plugin-only
or Telegram-only searches, set `"src": "plugin"` or `"src": "tg"`.

When using the raw request, reproduce the helper's policy behavior before
showing anything to the user. Extract candidates from
`.data.merged_by_type.quark[]`. Keep these fields: `note` as title, `url`,
`password`, `source`, `datetime`, and `images` when present. Clean the list:

- Keep only URLs matching `https://pan.quark.cn/s/<id>`.
- Strip query strings and whitespace from share URLs.
- Deduplicate by cleaned URL.
- Remove obvious non-matches and empty titles.
- Cap the displayed list to the requested maximum.
- Mark candidates whose title does not contain the keyword as `filtered`.
- Mark candidates matching configured blocked title patterns as `blocked`.
- Redact URLs for every status except `transferable`.

Default policy lives at `references/policy.default.json`. A project or user may
provide a stricter policy file with source allowlists or trusted internal
endpoint hosts. The default public policy treats `s.panhunt.com` as a public
endpoint. Public endpoint results become `transferable` only when they have no
blocked/filter reasons and match at least one programmatic allow condition:
trusted endpoint host, allowlisted source, or an allowed public-material title
pattern such as government reports, white papers, manuals, open data, open
source, public domain, or Creative Commons markers. Ordinary title matches from
public endpoints are `needs_authorization` and their URLs stay redacted.

Return exactly one selected Quark URL when `selected` is present. Include the
title, source, and verification summary. If `--save` was requested, also report
the save result from `save_result`.

If `selected` is present and `save_prompt.available` is true, ask the user
whether to save it after reporting the link. Use the prompt wording from
`save_prompt.message` when present, for example: `回复 1 保存到 /z-sync`. Do not
save immediately unless the user has already asked to save/sync/collect/archive/
transfer, or unless the user's next reply is exactly `1` in response to this
save prompt. When the user replies `1`, rerun the same search command with the
same keyword, source, policy, and any previous `--content-choice`, adding
`--save` and the same `--save-folder` if one was used.

If the helper returns `needs_user_selection: true`, report the numbered
`selection_options` with their labels, representative titles, sources, and
candidate counts, then ask the user to choose one number. Do not show any share
URL until the user has selected an option and the rerun returns `selected`.

When strong verification sees an authentication failure such as `not_logged_in`,
`认证失败`, `访问被拒绝`, HTTP `401`, HTTP `403`, or `Cookie过期`, the helper clears
`cookies.json`, emits a fresh `quark_login_required` QR-code event, waits for the
user to scan, and retries the same share verification once. In gateway chats,
send the emitted `qr_code_path` image immediately with `MEDIA:<path>` and then
continue after login completes; do not treat the first auth failure as a dead
share until the retry also fails or the QR login times out.

## Batch / Follow-up Handling

When the user provides multiple PanSou keywords in one message, process them as a batch but keep each keyword's deterministic helper run independent. Use the same endpoint, source mode, policy, verification mode, and save folder unless the user gives per-item overrides. Summarize each item separately with one of these states: selected link, needs content selection, no selected candidate, or save result.

If a previous response reported several verified selected links and ended with save prompts, interpret a follow-up like `保存全部`, `全部保存`, or `save all` as an explicit request to save every previously reported selected item that had `save_prompt.available: true`. Rerun the helper once per item with the same keyword and any prior `--content-choice`, adding `--save` and the same `--save-folder` if one was used. Do not include keywords that had no selected result, were only selection prompts, or were explicitly declined.

If the user gives compact choices such as `海街日记 1` and `比海更深 1`, treat the trailing number as that keyword's `--content-choice` and rerun each selected keyword. If the same message also includes `保存 <keyword>`, add `--save` for that item. When reporting batch saves, include destination folder, saved item names, and any partial failures; do not claim all succeeded unless every helper result has `save_result.ok: true`.

## Result Handling

After the search step, report the one selected link:

- title
- URL
- source
- title match status
- link verification status

Also report a short policy summary, for example: `1 selected; 16 transferable,
0 filtered, 0 blocked`. Never report redacted URLs for non-transferable
candidates. If PanSou returns no `.data.merged_by_type.quark`, or the helper
returns no `selected`, say that no verified Quark link was found and suggest
refining the keyword, switching `src`, or adjusting the policy.

When saving was requested, report whether `quarkpan` saved the selected link
successfully based on `save_result`. Include the destination folder, number
of files, and saved item names if visible in the command output. If saving
fails, include the visible `quarkpan` failure message and do not invent a
replacement link.

When a prior response ended with a save prompt and the user replies `1`, treat
that as a request to save the prior selected item. Do not reinterpret `1` as a
new search keyword or content-selection choice unless the active prompt was a
content selection prompt.

## Failure Handling

- User shorthand: if the user says `pansou, <keyword>` or `PanSou，<keyword>`, treat `<keyword>` as the search keyword and run the normal `--one --verify-link` flow. Do not ask what PanSou means.
- When a verified selected result has just been shown with `save_prompt.available: true`, interpret a following exact `1` as confirmation to rerun the same keyword/content choice with `--save`; do not treat it as a new content-selection choice or search keyword.
- Missing keyword: ask for the keyword.
- Policy helper failure: report the helper error and do not fall back to saving
  raw PanSou results unless policy behavior is reproduced manually.
- No `selected` candidate: stop without outputting a link.
- PanSou HTTP/network failure: report the endpoint and status/error, then ask
  whether to retry later or use another PanSou endpoint.
- PanSou schema changes: inspect the JSON shape, extract only Quark URLs if
  still obvious, otherwise stop and report the schema mismatch.
- Link verification failure: if another `transferable` candidate exists, the
  helper should choose it; otherwise report the failed verification and do not
  invent a working link.
- Save failure: report `save_result.reason`, `stdout`, or `stderr`. If
  `quarkpan` cannot be installed because the helper attempted
  `python3 -m pip install --user quarkpan` from a virtualenv where user
  site-packages are hidden, install the missing package into the active
  environment instead (for example `python3 -m pip install quarkpan`) and retry
  the helper. If login then fails with a missing QR/image dependency such as
  `No module named 'PIL'`, install Pillow in the same environment with
  `python3 -m pip install Pillow` and retry. If login is missing, start the
  login/check command as a tracked background process, send the generated
  `qr_code_path` PNG as native media (`MEDIA:<path>` in Telegram), then ask the
  user to scan and confirm before rerunning the search/save. Because QR codes
  expire quickly, do not only report the local path.
- Weak verification: tell the user the URL page responded but share contents but share contents
  were not confirmed. Ask them to log in with `quarkpan` in the same config
  context if content-level validation is required.
- Legal or access concerns: follow the deterministic policy gate. If the user
  explicitly requests bypass or unlawful access, stop and ask for user-owned,
  licensed, public-domain, or otherwise authorized material.
