Three new flags for export_all_chats.py:
- -i / --incremental: reads existing JSON, appends only new messages
(deduplicates by local_id, preserves transcription field on merge)
- --start / --end: filter messages by date range (YYYY-MM-DD or timestamp)
passes start_ts/end_ts directly to mcp_server._query_messages
- --dry-run: preview mode (shows counts without writing files)
Voice transcription in incremental mode only processes newly appended
voice messages — existing transcribed entries are untouched.
Add structured parsing for transfer messages so they no longer fall
through to the generic `[链接/文件]` fallback in chat history exports.
Mirrors the dispatch + helper pattern PR #65 (merged-forward type=19)
established for `base_type=49` appmsg sub-types.
## What is added
**Helpers (mcp_server.py):**
- `_TRANSFER_PAYSUBTYPE_LABEL` — maps the 6 community-consensus paysubtypes
(1 发起 / 3 已收款 / 4 已退还 / 5 过期已退还 / 7 待领取 / 8 已领取);
unknown values degrade to `未知(paysubtype=N)` so a new variant in a
future WeChat build is visible rather than silently dropped.
- `_extract_transfer_info(appmsg)` — pulls fields out of `<wcpayinfo>`,
with snake/camelCase fallback (`feedesc`/`feeDesc`, `pay_memo`/`paymemo`)
observed across WeChat versions.
- `_format_transfer_message_text(appmsg, title)` — one-line render
for chat history: `[转账·已收款] ¥100.00 备注: lunch`.
**Dispatch (mcp_server.py):**
- `_format_app_message_text` gains an `app_type == 2000` branch that
routes to `_format_transfer_message_text`. `get_chat_history`,
`export_chat`, `export_all_chats` and `monitor_web` all inherit
automatically.
**New MCP tool (mcp_server.py):**
- `decode_transfer(chat_name, local_id, create_time=0)` — full
structured view: direction, amount, memo, payer/receiver wxid,
transfer id, transcation id, begin/invalid timestamps. Uses the
same multi-shard scan + ambiguity-by-create_time pattern as
`decode_file_message` / `decode_record_item`.
**CLI wrapper:**
- `decode_transfer.py` at the repo root — argparse wrapper that prints
the same text as the MCP tool, returning non-zero exit when the
message can't be decoded (script-friendly).
**JSON export (chat_export_helpers.py + export_chat.py + export_all_chats.py):**
- `_extract_content` now returns `(rendered, extras)`. `extras` carries
structured fields when a message type has more signal than the
human-readable string (currently: transfers → `type:"transfer" +
transfer:{direction, fee_desc, pay_memo, ...}`). The channel is
forward-compatible — future additions (video号 metadata, expanded
merged-forward, etc.) flow through the same shape without changing
the caller signature. JSON consumers that only read `content` are
unaffected; the change is additive.
**monitor_web (monitor_web.py):**
- Backend dispatch branch + orange-yellow `.msg-transfer` card CSS +
`renderRich` JS handler.
## Tests
12 new cases in `tests/test_record_decoders.py`:
- `TransferPaysubTypeLabelTests` — locks the 6-value label table.
- `ExtractTransferInfoTests` (6 cases) — full field round-trip, missing
`<wcpayinfo>` fallback, snake/camelCase variants, unknown paysubtype
degradation, empty paysubtype handling.
- `FormatTransferMessageTextTests` (4 cases) — initiate / received-with-memo /
missing-wcpayinfo / missing-fee-desc.
- `AppMessageDispatchTransferTests` — `_format_app_message_text` routes
type=2000 correctly so `get_chat_history` / `export_chat` both pick
it up.
All fixtures use synthetic placeholder values (`wxid_payer_synth`,
`¥100.00`, `1` + 27×`0`); no real PII or transaction IDs.
## Scope
7 files, +546 / -15 (additions only — no behavior change for existing
message types). All 180 tests pass locally (168 baseline + 12 new).
* Add export_all_chats.py: batch export all WeChat chats to JSON
Mirrors export_chat.py functionality to export every chat in the
decrypted WeChat database at once. Output format is byte-for-byte
identical to export_chat.py.
Usage: python3 export_all_chats.py [output_dir]
- Reads all sessions from decrypted/session/session.db
- Uses the same content extraction pipeline as export_chat.py:
_resolve_sender, _extract_content, _msg_type_str, sticker/video/system
- Outputs group_<display>.json or single_<display>.json with same schema
- Progress reporting every 100 exports with summary at end
* refactor: 将 7 个重复 helper 函数提取到 chat_export_helpers.py
根据 PR #77 review 反馈,将 export_chat.py 和 export_all_chats.py 中
逐字复制的消息格式化函数提取到共享模块 chat_export_helpers.py。
提取的函数:
MSG_TYPE_MAP, _msg_type_str, _resolve_sender,
_decode_sticker_desc, _format_sticker_message,
_format_system_message, _format_video_message, _extract_content
两个导出脚本现在从 chat_export_helpers import 所需函数,
消除代码漂移风险。