diff --git a/example.js b/example.js index d0d9632..347e7c6 100644 --- a/example.js +++ b/example.js @@ -140,6 +140,10 @@ client.on('message', async msg => { const attachmentData = await quotedMsg.downloadMedia(); client.sendMessage(msg.from, attachmentData, { caption: 'Here\'s your requested media.' }); } + if (quotedMsg.hasMedia && quotedMsg.type === 'audio') { + const audio = await quotedMsg.downloadMedia(); + await client.sendMessage(msg.from, audio, { sendAudioAsVoice: true }); + } } else if (msg.body === '!isviewonce' && msg.hasQuotedMsg) { const quotedMsg = await msg.getQuotedMessage(); if (quotedMsg.hasMedia) { diff --git a/index.d.ts b/index.d.ts index ea8be4b..73109a3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -904,7 +904,7 @@ declare namespace WAWebJS { export interface MessageSendOptions { /** Show links preview. Has no effect on multi-device accounts. */ linkPreview?: boolean - /** Send audio as voice message */ + /** Send audio as voice message with a generated waveform */ sendAudioAsVoice?: boolean /** Send video as gif */ sendVideoAsGif?: boolean diff --git a/src/Client.js b/src/Client.js index 490b70d..46e55a9 100644 --- a/src/Client.js +++ b/src/Client.js @@ -785,7 +785,7 @@ class Client extends EventEmitter { * Message options. * @typedef {Object} MessageSendOptions * @property {boolean} [linkPreview=true] - Show links preview. Has no effect on multi-device accounts. - * @property {boolean} [sendAudioAsVoice=false] - Send audio as voice message + * @property {boolean} [sendAudioAsVoice=false] - Send audio as voice message with a generated waveform * @property {boolean} [sendVideoAsGif=false] - Send video as gif * @property {boolean} [sendMediaAsSticker=false] - Send media as a sticker * @property {boolean} [sendMediaAsDocument=false] - Send media as a document diff --git a/src/util/Injected.js b/src/util/Injected.js index 28ca4b4..cb9a0a0 100644 --- a/src/util/Injected.js +++ b/src/util/Injected.js @@ -390,6 +390,9 @@ exports.LoadUtils = () => { if (forceVoice && mediaData.type === 'audio') { mediaData.type = 'ptt'; + const waveform = mediaObject.contentInfo.waveform; + mediaData.waveform = + waveform ?? await window.WWebJS.generateWaveform(file); } if (forceGif && mediaData.type === 'video') { @@ -632,6 +635,42 @@ exports.LoadUtils = () => { return result; }; + /** + * Referenced from and modified: + * @see https://github.com/wppconnect-team/wa-js/commit/290ebfefe6021b3d17f7fdfdda5545bb0473b26f + */ + window.WWebJS.generateWaveform = async (audioFile) => { + try { + const audioData = await audioFile.arrayBuffer(); + const audioContext = new AudioContext(); + const audioBuffer = await audioContext.decodeAudioData(audioData); + + const rawData = audioBuffer.getChannelData(0); + const samples = 64; + const blockSize = Math.floor(rawData.length / samples); + const filteredData = []; + for (let i = 0; i < samples; i++) { + const blockStart = blockSize * i; + let sum = 0; + for (let j = 0; j < blockSize; j++) { + sum = sum + Math.abs(rawData[blockStart + j]); + } + filteredData.push(sum / blockSize); + } + + const multiplier = Math.pow(Math.max(...filteredData), -1); + const normalizedData = filteredData.map((n) => n * multiplier); + + const waveform = new Uint8Array( + normalizedData.map((n) => Math.floor(100 * n)) + ); + + return waveform; + } catch (e) { + return undefined; + } + }; + window.WWebJS.sendClearChat = async (chatId) => { let chat = window.Store.Chat.get(chatId); if (chat !== undefined) {