wechat_msg_crawler/wechat_cli/commands/contacts.py
canghe e64006bafe Initial release: wechat-cli v0.2.0
A CLI tool to query local WeChat data with 11 commands:
sessions, history, search, contacts, members, stats, export,
favorites, unread, new-messages, and init.

Features:
- Self-contained init with key extraction (no external deps)
- On-the-fly SQLCipher decryption with caching
- JSON output by default for LLM/AI tool integration
- Message type filtering and chat statistics
- Markdown/txt export for conversations
- Cross-platform: macOS, Windows, Linux
2026-04-04 11:10:10 +08:00

92 lines
3.2 KiB
Python
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.

"""contacts 命令 — 搜索或查看联系人"""
import click
from ..core.contacts import get_contact_full, get_contact_names, resolve_username, get_contact_detail
from ..output.formatter import output
@click.command("contacts")
@click.option("--query", default="", help="搜索关键词匹配昵称、备注、wxid")
@click.option("--detail", default=None, help="查看联系人详情(传入昵称/备注/wxid")
@click.option("--limit", default=50, help="返回数量")
@click.option("--format", "fmt", default="json", type=click.Choice(["json", "text"]), help="输出格式")
@click.pass_context
def contacts(ctx, query, detail, limit, fmt):
"""搜索或列出联系人
\b
示例:
wechat-cli contacts --query "" # 搜索联系人
wechat-cli contacts --detail "张三" # 查看联系人详情
wechat-cli contacts --detail "wxid_xxx" # 通过 wxid 查看
"""
app = ctx.obj
if detail:
_show_detail(app, detail, fmt)
return
names = get_contact_names(app.cache, app.decrypted_dir)
full = get_contact_full(app.cache, app.decrypted_dir)
if query:
q_lower = query.lower()
matched = [c for c in full if q_lower in c.get('nick_name', '').lower()
or q_lower in c.get('remark', '').lower()
or q_lower in c.get('username', '').lower()]
else:
matched = full
matched = matched[:limit]
if fmt == 'json':
output(matched, 'json')
else:
header = f"找到 {len(matched)} 个联系人:"
lines = []
for c in matched:
display = c['remark'] or c['nick_name'] or c['username']
line = f"{display} ({c['username']})"
if c['remark']:
line += f" 备注: {c['remark']}"
lines.append(line)
output(header + "\n\n" + "\n".join(lines), 'text')
def _show_detail(app, name_or_id, fmt):
"""显示联系人详情。"""
names = get_contact_names(app.cache, app.decrypted_dir)
# 尝试解析为 username
username = resolve_username(name_or_id, app.cache, app.decrypted_dir)
if not username:
# 直接用原始输入试试
username = name_or_id
info = get_contact_detail(username, app.cache, app.decrypted_dir)
if not info:
click.echo(f"找不到联系人: {name_or_id}", err=True)
return
if fmt == 'json':
output(info, 'json')
else:
lines = [f"联系人详情: {info['nick_name']}"]
if info['remark']:
lines.append(f"备注: {info['remark']}")
if info['alias']:
lines.append(f"微信号: {info['alias']}")
lines.append(f"wxid: {info['username']}")
if info['description']:
lines.append(f"个性签名: {info['description']}")
if info['is_group']:
lines.append("类型: 群聊")
elif info['is_subscription']:
lines.append("类型: 公众号")
elif info['verify_flag'] and info['verify_flag'] >= 8:
lines.append("类型: 企业认证")
if info['avatar']:
lines.append(f"头像: {info['avatar']}")
output("\n".join(lines), 'text')