Skip to content

Feature proposal: local per-message media manifest and transcript links #6

Closed

Description

@ShiTan-677

export_chat.py currently renders image messages as [Image]. The separate media exporter copies plaintext cache images and skips encrypted .dat originals, but does not associate exported assets with individual transcript messages.

Would a per-message local asset manifest be a useful first step toward linking transcripts and images?

A possible format could include:

  • Message identity scoped to an account snapshot: shard + local ID, with server ID when available. Server ID alone may be absent or insufficient for every message.
  • Asset kind, resolution status (resolved, not_found, encrypted_unsupported) and a relative exported path when available.
  • A resolver that uses verified resource-index relationships rather than assuming that the message XML MD5 appears in the filename.

TXT could render a relative path; Markdown/HTML could provide links or previews. Missing or unsupported assets would retain the current placeholder with an explicit status. Paths would stay local, and the manifest would exclude raw keys, image AES keys, authentication fields and CDN URLs.

This should be separate from implementing a decoder for encrypted image originals. That work needs format-specific fixtures and verification of the correct message-to-asset mapping. A collision-safe media layout is also helpful, but exporting all account media is not a substitute for selecting assets for one conversation and date window.

I can contribute a small manifest/export change once the intended scope and resource mapping are agreed. This proposal contains no private chat records or image encryption metadata.

Activity

  1. freanocank commented on Oct 13, 2026

    @freanocank
    Owner

    Thanks for the proposal. A per-message local manifest is a useful next step, and the first-increment contract is now documented in docs/media-manifest-proposal.md.

    The attachment prerequisites from #5 and #10 are adopted through #15: same-named attachments retain their directories, and Windows attachment lookup uses the original account rather than the database mirror.

    For the manifest, please scope identity to account snapshot + conversation/table + shard + local ID, with an optional server ID. Local IDs can repeat across both shards and conversation tables. Resolved entries should use paths relative to the export root; missing, ambiguous and encrypted/unsupported assets must remain explicit. The resolver should use a demonstrated resource-index relationship, without assuming that an XML MD5 is the asset filename. Start with the JSON sidecar and TXT paths; Markdown/HTML previews and encrypted-image decoding can follow separately.

    The missing prerequisite is a minimal, verified mapping fixture: table definitions and synthetic rows showing message -> resource index -> local image, with the tested WeChat version/platform. Please exclude private messages, account identifiers, keys, authentication fields and CDN URLs. The public image implementations inspected so far rely on filename/MD5 heuristics and do not establish that relationship for this repository.

    Keeping this issue open until those fixtures, the resolver and transcript links meet the documented acceptance cases. This is an accepted feature direction, not a completed image-association implementation.

  2. freanocank commented on Oct 13, 2026

    @freanocank
    Owner

    Implemented and merged in #16, with repeated-export asset isolation in #17.

    export_chat.py CONTACT --with-media --no-transcribe -o chat.html now creates the transcript, chat.media.json and a fresh chat.assets-<export-id>/ directory recorded as assets_directory in the manifest. Earlier export directories are preserved; the current directory never inherits images from a previous date window. When none of the selected images is readable, only the transcript and sidecar are produced. TXT includes relative paths; Markdown and HTML embed supported local images. Only image messages belonging to the selected conversation/date window are exported.

    The resolver uses the verified resource-index relationship: ChatName2Id / MessageResourceInfo, protobuf field 2.1, then the registered image_hardlink_info_v4 filenames and dir2id directories. It does not guess the filename from the message XML MD5. Snapshot/conversation/table/shard/local-ID identity handles missing server IDs and repeated local IDs. Missing, ambiguous, unknown-profile and encrypted assets keep explicit statuses; the original placeholder remains visible. Copied files and sidecars stay private, with no raw packed payloads, keys, authentication fields, CDN URLs or absolute source paths.

    Validation includes 24 new synthetic cases and complete CLI exports in all three formats. All four macOS/Windows × Python 3.10/3.13 CI jobs passed: Windows 233 passed; macOS 232 passed with the Windows-only test skipped. A read-only native macOS WeChat 4.1.15 check confirmed an actual message/index/file association, and a browser smoke test confirmed the generated HTML loads its relative image. No private data was included in the fixtures or PR.

    The former proposal document now documents the implemented interface and supported index profile. Encrypted-image decoding remains separate as originally scoped; existing encrypted originals are identified as encrypted_unsupported rather than linked to an incorrect plaintext file. This completes the manifest/transcript-link increment, so closing the issue. Thanks for the proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions