feat: send audio with waveform (#2309)

* added generateWaveform

* docs updated

* added usage example

* ESLint fix

* fixed: undefined returned on waveform generation failure

* fix: ESLint
This commit is contained in:
alechkos 2023-08-10 14:37:45 +03:00 • committed by GitHub
commit df1b070d54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 2 deletions

View file

@ -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) {

2
index.d.ts vendored
View file

@ -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

View file

@ -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

View file

@ -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) {