Files
wechat-cli/wechat_cli/commands/export.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

102 lines
3.5 KiB
Python
Raw Permalink 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.
"""export 命令 — 导出聊天记录为 markdown 或 txt"""
import click
from datetime import datetime
from ..core.contacts import get_contact_names
from ..core.messages import (
collect_chat_history,
parse_time_range,
resolve_chat_context,
validate_pagination,
)
from ..output.formatter import output
@click.command("export")
@click.argument("chat_name")
@click.option("--format", "fmt", default="markdown", type=click.Choice(["markdown", "txt"]), help="导出格式")
@click.option("--output", "output_path", default=None, help="输出文件路径(默认输出到 stdout")
@click.option("--start-time", default="", help="起始时间 YYYY-MM-DD [HH:MM[:SS]]")
@click.option("--end-time", default="", help="结束时间 YYYY-MM-DD [HH:MM[:SS]]")
@click.option("--limit", default=500, help="导出消息数量")
@click.pass_context
def export(ctx, chat_name, fmt, output_path, start_time, end_time, limit):
"""导出聊天记录为 markdown 或纯文本
\b
示例:
wechat-cli export "张三" --format markdown
wechat-cli export "AI交流群" --format txt --output chat.txt
wechat-cli export "张三" --start-time "2026-04-01" --limit 1000
"""
app = ctx.obj
try:
validate_pagination(limit, 0, limit_max=None)
start_ts, end_ts = parse_time_range(start_time, end_time)
except ValueError as e:
click.echo(f"错误: {e}", err=True)
ctx.exit(2)
chat_ctx = resolve_chat_context(chat_name, app.msg_db_keys, app.cache, app.decrypted_dir)
if not chat_ctx:
click.echo(f"找不到聊天对象: {chat_name}", err=True)
ctx.exit(1)
if not chat_ctx['db_path']:
click.echo(f"找不到 {chat_ctx['display_name']} 的消息记录", err=True)
ctx.exit(1)
names = get_contact_names(app.cache, app.decrypted_dir)
lines, failures = collect_chat_history(
chat_ctx, names, app.display_name_fn,
start_ts=start_ts, end_ts=end_ts, limit=limit, offset=0,
)
if not lines:
click.echo(f"{chat_ctx['display_name']} 无消息记录", err=True)
ctx.exit(0)
now = datetime.now().strftime('%Y-%m-%d %H:%M')
chat_type = "群聊" if chat_ctx['is_group'] else "私聊"
time_range = f"{start_time or '最早'} ~ {end_time or '最新'}"
if fmt == 'markdown':
content = _format_markdown(chat_ctx['display_name'], chat_type, time_range, now, lines)
else:
content = _format_txt(chat_ctx['display_name'], chat_type, time_range, now, lines)
if output_path:
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
if not content.endswith('\n'):
f.write('\n')
click.echo(f"已导出到: {output_path}{len(lines)} 条消息)", err=True)
else:
output(content, 'text')
def _format_markdown(display_name, chat_type, time_range, export_time, lines):
header = (
f"# 聊天记录: {display_name}\n\n"
f"**时间范围:** {time_range}\n\n"
f"**导出时间:** {export_time}\n\n"
f"**消息数量:** {len(lines)}\n\n"
f"**类型:** {chat_type}\n\n---\n"
)
body = "\n".join(f"- {line}" for line in lines)
return header + body
def _format_txt(display_name, chat_type, time_range, export_time, lines):
header = (
f"聊天记录: {display_name}\n"
f"类型: {chat_type}\n"
f"时间范围: {time_range}\n"
f"导出时间: {export_time}\n"
f"消息数量: {len(lines)}\n"
f"{'=' * 60}"
)
body = "\n".join(lines)
return header + "\n" + body