diff --git a/nanobot/channels/whatsapp/runtime.py b/nanobot/channels/whatsapp/runtime.py index e25a73e99..dcd9a5740 100644 --- a/nanobot/channels/whatsapp/runtime.py +++ b/nanobot/channels/whatsapp/runtime.py @@ -55,6 +55,10 @@ _JID_RE = re.compile(r"^(?P[^@]+)@(?P[^@]+)$") _LEGACY_BRIDGE_CONFIG_FIELDS = ("bridgeUrl", "bridgeToken", "bridge_url", "bridge_token") # OGG is intentionally excluded: WhatsApp accepts only mono Opus, which MIME sniffing cannot prove. _DIRECT_AUDIO_MIMETYPES = {"audio/aac", "audio/amr", "audio/mp4", "audio/mpeg"} +_MIMETYPE_ALIASES = { + "audio/x-hx-aac-adts": "audio/aac", + "audio/x-m4a": "audio/mp4", +} def _default_database_path() -> Path: @@ -450,7 +454,8 @@ class WhatsAppChannel(BaseChannel): detected = None if isinstance(detected, str) and "/" in detected: - return detected.partition(";")[0].strip().lower() + mimetype = detected.partition(";")[0].strip().lower() + return _MIMETYPE_ALIASES.get(mimetype, mimetype) guessed, _ = mimetypes.guess_type(path) return guessed or "application/octet-stream" diff --git a/nanobot/channels/whatsapp/tests/test_whatsapp_channel.py b/nanobot/channels/whatsapp/tests/test_whatsapp_channel.py index ba6cc06cd..2da369802 100644 --- a/nanobot/channels/whatsapp/tests/test_whatsapp_channel.py +++ b/nanobot/channels/whatsapp/tests/test_whatsapp_channel.py @@ -286,6 +286,39 @@ async def test_send_unsupported_ogg_audio_as_document(monkeypatch) -> None: client.send_audio.assert_not_awaited() +@pytest.mark.parametrize( + ("detected_mimetype", "filename"), + [ + ("audio/x-m4a", "recording.m4a"), + ("audio/x-hx-aac-adts", "recording.aac"), + ], +) +@pytest.mark.asyncio +async def test_send_supported_audio_magic_aliases_inline( + monkeypatch, detected_mimetype: str, filename: str +) -> None: + _patch_neonize_api( + monkeypatch, + detect_mime=lambda path, *, mime: detected_mimetype, + ) + client = _make_send_client() + ch = _make_channel() + ch._client = client + ch._connected = True + + await ch.send( + OutboundMessage( + channel="whatsapp", + chat_id="12345@s.whatsapp.net", + content="", + media=[filename], + ) + ) + + client.send_audio.assert_awaited_once_with(("12345", "s.whatsapp.net"), filename) + client.send_document.assert_not_awaited() + + @pytest.mark.asyncio async def test_send_when_disconnected_raises() -> None: ch = _make_channel()