fix(whatsapp): corrige content-type audio/opus e extensão para OGG
- MediaHandler: adiciona sanitize_content_type que normaliza audio/opus → audio/ogg - MediaHandler: detect_extension retorna .ogg (não .mp3) para áudios WhatsApp - MediaHandler: final_filename força extensão .ogg em áudios que chegam com .mp3 - Attachment: normalize_opus_blob_content_type! agora verifica apenas content_type (remove checagem de extensão de filename que impedia normalização de blobs .mp3) - Attachment: audio_metadata chama normalize_opus_blob_content_type! para corrigir blobs existentes na primeira vez que são acessados (lazy fix) WhatsApp envia áudio como container OGG/Opus (bytes OggS = 4f 67 67 53), mas declarava mimetype audio/opus. Browsers não conseguem reproduzir container OGG via MIME audio/opus — precisam de audio/ogg. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ec6cfc317d
commit
5d3ce4e565
@ -114,6 +114,7 @@ class Attachment < ApplicationRecord
|
||||
end
|
||||
|
||||
def audio_metadata
|
||||
normalize_opus_blob_content_type!
|
||||
audio_file_data = base_data.merge(file_metadata)
|
||||
audio_file_data.merge(
|
||||
{
|
||||
@ -205,12 +206,12 @@ class Attachment < ApplicationRecord
|
||||
{ host: host, protocol: uri.scheme }
|
||||
end
|
||||
|
||||
# Marcel gem may detect OGG/Opus files as audio/opus instead of audio/ogg.
|
||||
# Lazily normalize existing blobs so presigned URLs serve the correct Content-Type.
|
||||
# Only applies to .ogg files — .opus files legitimately use audio/opus.
|
||||
# WhatsApp audio arrives as OGG/Opus container. Some paths save it as audio/opus
|
||||
# (raw Opus MIME type) which browsers cannot play via <audio> tag.
|
||||
# Lazily normalise to audio/ogg on first access, regardless of filename extension.
|
||||
def normalize_opus_blob_content_type!
|
||||
blob = file.blob
|
||||
return unless blob.content_type == 'audio/opus' && blob.filename.to_s.end_with?('.ogg')
|
||||
return unless blob.content_type == 'audio/opus'
|
||||
|
||||
blob.update_column(:content_type, 'audio/ogg') # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
@ -14,7 +14,7 @@ class Whatsapp::Wuzapi::MediaHandler
|
||||
file: {
|
||||
io: file_io,
|
||||
filename: final_filename(attachment_data),
|
||||
content_type: attachment_data[:mimetype] || 'application/octet-stream'
|
||||
content_type: sanitize_content_type(attachment_data[:mimetype], @parser.message_type)
|
||||
}
|
||||
)
|
||||
end
|
||||
@ -68,12 +68,22 @@ class Whatsapp::Wuzapi::MediaHandler
|
||||
name = data[:file_name] || "wuzapi_#{Time.now.to_i}"
|
||||
ext = File.extname(name)
|
||||
ext = detect_extension(data[:mimetype], @parser.message_type) if ext.blank?
|
||||
# Normalise audio extension: WhatsApp always sends OGG/Opus, never MP3
|
||||
ext = '.ogg' if @parser.message_type == :audio && ext == '.mp3'
|
||||
"#{File.basename(name, '.*')}#{ext}"
|
||||
end
|
||||
|
||||
def sanitize_content_type(mimetype, type)
|
||||
# WhatsApp audio is OGG-wrapped Opus. audio/opus is raw Opus (wrong container header).
|
||||
# Saving as audio/ogg ensures browsers can play via <audio> without issues.
|
||||
return 'audio/ogg' if type == :audio && mimetype.to_s.include?('opus')
|
||||
|
||||
mimetype || 'application/octet-stream'
|
||||
end
|
||||
|
||||
def detect_extension(mimetype, type)
|
||||
return '.jpg' if type == :image || type == :sticker
|
||||
return '.mp3' if type == :audio
|
||||
return '.ogg' if type == :audio
|
||||
return '.mp4' if type == :video
|
||||
|
||||
case mimetype
|
||||
|
||||
Loading…
Reference in New Issue
Block a user