Skip to content

fix: support gif media type in downloads#274

Merged
steipete merged 2 commits into
openclaw:mainfrom
larskluge:fix/gif-media-download
Jun 10, 2026
Merged

fix: support gif media type in downloads#274
steipete merged 2 commits into
openclaw:mainfrom
larskluge:fix/gif-media-download

Conversation

@larskluge

@larskluge larskluge commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Problem

extractMedia labels video messages carrying the gif-playback hint as media_type "gif", but MediaTypeFromString has no case for it. As a result every gif fails media download — both via wacli media download and via the background workers of sync --download-media — with unsupported media type: gif, before any network request is made. local_path never gets set for these messages.

Fix

Map "gif" to whatsmeow.MediaVideo: WhatsApp gifs are stored and encrypted as regular videos (the gif flag is only a playback hint). Same label-remap precedent as "sticker"MediaImage in the same switch.

Real behavior proof

Before/after run against a real gif message that the background downloader had skipped (media download in --read-only direct-download mode; same store, same message, run back to back; group JID and message id redacted):

$ wacli-main --read-only --json media download --store <store> \
    --chat <redacted-group-jid> --id <redacted-msg-id> --output /tmp/gif-proof.mp4
{"success":false,"data":null,"error":"unsupported media type: gif"}
# exit 1

$ wacli-pr --read-only --json media download --store <store> \
    --chat <redacted-group-jid> --id <redacted-msg-id> --output /tmp/gif-proof.mp4
{"success":true,"data":{"bytes":1268887,"chat":"<redacted-group-jid>","downloaded":true,"id":"<redacted-msg-id>","media_type":"gif","mime_type":"video/mp4","path":"/tmp/gif-proof.mp4","read_only":true,"recorded":false},"error":null}
# exit 0

$ ffprobe -v error -show_entries format=format_name,duration,size:stream=codec_name,width,height \
    -of default=noprint_wrappers=1 gif-proof.mp4
codec_name=h264
width=576
height=1024
format_name=mov,mp4,m4a,3gp,3g2,mj2
duration=6.066667
size=1268887
  • wacli-main = built from current main (be2d22f); wacli-pr = main + this PR (9116ff7). Only this PR's 2-file diff differs between the binaries.
  • Downloaded size (1,268,887 bytes) matches the message's recorded file_length exactly, and the direct-download path verifies file_sha256 internally before writing — so this is the original media, decrypted correctly with the video key type.
  • Coverage context from the originating store: gif messages were 0/18 ever auto-downloaded while every other media type had normal coverage (image 2401/2830, video 757/821, audio 11/14, sticker 8/10, document 59/63) — consistent with a hard block on the gif label rather than network flakiness.

Test

Extended TestMediaTypeFromString to assert the resolved whatsmeow.MediaType for every supported label, including gifMediaVideo. The new assertion fails on main with unsupported media type: gif and passes with this change. Full suite (go build ./... && go vet ./... && go test ./...) is green.

🤖 Generated with Claude Code

@clawsweeper

clawsweeper Bot commented Jun 7, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed June 7, 2026, 8:08 PM ET / 00:08 UTC.

Summary
The PR maps gif media labels to whatsmeow.MediaVideo in MediaTypeFromString and expands the media type unit test to assert concrete label mappings.

Reproducibility: yes. with source inspection and the contributor's redacted terminal proof: current main stores gif labels but rejects them before download. I did not run a live WhatsApp download in this read-only review.

Review metrics: 1 noteworthy metric.

  • Patch surface: 2 files changed, +17/-2. The diff is limited to one media helper and its unit test, so review can focus on the media-type mapping.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Next step before merge

  • No automated repair is needed; the remaining action is ordinary maintainer/check-gated PR review.

Security
Cleared: The diff only changes an internal media-type mapping and unit test, with no dependency, workflow, credential, or supply-chain surface added.

Review details

Best possible solution:

Land the narrow gif to video mapping with the regression test after normal CI/maintainer checks, preserving the existing hash, size, and direct-download verification paths.

Do we have a high-confidence way to reproduce the issue?

Yes, with source inspection and the contributor's redacted terminal proof: current main stores gif labels but rejects them before download. I did not run a live WhatsApp download in this read-only review.

Is this the best way to solve the issue?

Yes, mapping gif to MediaVideo is the narrowest maintainable fix because the repository already labels gif-playback videos as gif for UX while WhatsApp stores and decrypts them as videos.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against be2d22fe9d8c.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted terminal before/after output from a real gif media message, plus ffprobe output showing the downloaded file after the fix.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes redacted terminal before/after output from a real gif media message, plus ffprobe output showing the downloaded file after the fix.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This fixes a real media-download failure for WhatsApp gif messages, but the blast radius is limited to one media label path.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes redacted terminal before/after output from a real gif media message, plus ffprobe output showing the downloaded file after the fix.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted terminal before/after output from a real gif media message, plus ffprobe output showing the downloaded file after the fix.
Evidence reviewed

What I checked:

  • Repository policy read: Read the full repository AGENTS.md and applied its bugfix regression-test and minimal-dependency guidance to this review. (AGENTS.md:1, be2d22fe9d8c)
  • Current main stores GIF labels: extractMedia sets mediaType = "gif" when a WhatsApp video message has the gif-playback hint. (internal/wa/messages_media.go:27, be2d22fe9d8c)
  • Current main rejects that label: MediaTypeFromString on current main supports image, video, audio, document, and sticker, but no gif case; both connected and direct download paths call this helper before downloading. (internal/wa/media.go:42, be2d22fe9d8c)
  • PR implementation: PR head adds a case "gif" path that returns whatsmeow.MediaVideo, matching the existing video media key and direct-download mms-type behavior. (internal/wa/media.go:48, 9116ff739ac9)
  • Regression test: PR head changes TestMediaTypeFromString to assert concrete whatsmeow media types, including gif to MediaVideo. (internal/wa/media_test.go:25, 9116ff739ac9)
  • Real behavior proof: The PR body now includes redacted terminal before/after output for the same real gif message: current main returns unsupported media type: gif, the PR succeeds, and ffprobe verifies an h264 mp4 output with the reported size. (9116ff739ac9)

Likely related people:

  • Peter Steinberger: Blame shows the current MediaTypeFromString switch and the GifPlayback to gif labeling path both date to the v0.11.0 release commit. (role: introduced behavior / original area contributor; confidence: high; commits: 201f7adcaf16; files: internal/wa/media.go, internal/wa/messages_media.go)
  • Jason O'Neal: The latest current-main commit touching internal/wa/media.go bounded direct media HTTP downloads and added media timeout coverage. (role: recent adjacent media-download contributor; confidence: medium; commits: be2d22fe9d8c; files: internal/wa/media.go, internal/wa/media_timeout_test.go)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@larskluge larskluge closed this Jun 7, 2026
@larskluge larskluge reopened this Jun 7, 2026
@larskluge

Copy link
Copy Markdown
Contributor Author

Reopened — this was auto-closed by GitHub's cross-repo closing-keyword parsing (a PR description elsewhere contained "fix: #274" and closed this on merge). Not intentional; the fix stands as proposed.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 7, 2026
larskluge and others added 2 commits June 10, 2026 08:05
extractMedia labels video messages that have the gif-playback hint as
media_type "gif", but MediaTypeFromString had no case for it. Every gif
therefore failed both `wacli media download` and the background
`sync --download-media` workers with "unsupported media type: gif"
before any network request was made.

Map "gif" to whatsmeow.MediaVideo: WhatsApp gifs are stored and
encrypted as regular videos (same precedent as sticker -> MediaImage).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@steipete steipete force-pushed the fix/gif-media-download branch from 9116ff7 to ac18283 Compare June 10, 2026 07:17

@steipete steipete left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed implementation and maintainer follow-up. GIF playback videos keep the stored media_type label as gif, while download and decrypt use WhatsApp video media keys; local tests cover direct download, hashes, decrypt, and MMS mapping.

@steipete

Copy link
Copy Markdown
Collaborator

Maintainer proof after rebasing onto current main and adding the maintainer test/changelog commit.

  • Design: the stored media_type label stays gif for display/search/forwarding semantics. The download boundary maps that label to whatsmeow.MediaVideo, so GIF playback videos use WhatsApp video HKDF keys and mms-type=video; MIME/extension still come from the stored message metadata. Sticker mapping remains image-keyed, and unknown labels still error.
  • Current-main repro: go test -overlay /tmp/wacli-pr274-repro/overlay.json ./internal/wa -run 'Test(MediaTypeFromString|DownloadMediaDirectToFile)$' fails against origin/main with unsupported media type: gif in both TestMediaTypeFromString and the direct-download GIF case.
  • Fixed proof: go test ./internal/wa -run 'Test(MediaTypeFromString|DownloadMediaDirectToFile)$' passes and covers gif direct download using video keys, mms-type=video, encrypted hash, plaintext hash, HMAC/decrypt, and output bytes.
  • Local gate: pnpm -s docs:site, pnpm -s format:check, pnpm -s lint, pnpm -s test, pnpm -s build, git diff --check, go test -race ./internal/wa ./internal/app ./internal/store, goreleaser check --config .goreleaser.yaml, goreleaser check --config .goreleaser-linux-windows.yaml, and CI deadcode command all passed.
  • Live WhatsApp proof limitation: checked local wacli stores read-only; there are no named accounts and the default store has no gif media rows with complete metadata, so I could not safely produce a same-message live media download from this machine. The protocol fixture is the strongest available local proof here.
  • GitHub CI for head ac182832ecaf581e9f52f90fd77df18520810a8f: docker, linux-release-builds, and test all green.

Autoreview:

  • /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode local clean.
  • /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode branch --base origin/main clean.

@steipete steipete merged commit 7289a9f into openclaw:main Jun 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants