mirror of
https://github.com/cheveguerra/whatsapp-web.js.git
synced 2026-04-20 04:29:15 +00:00
Add support for sticker Name and author (#527)
* Added Sticker author and sticker name support This patch of Client.js includes support for sticker metadata * Docs: stickerName and stickerAuthor in MessageOpts * Hotfix_Sticker_Feature fixes a bug * Update global.html * updated * fixed comma * Fixed duplicate code * Fixing eslint * Fixing eslint again * eslint.... * fixing problem with eslint. * move sticker exif data filling to Utils.formatToWebpSticker() function * Update Client.js * Added temporary stuff * eslint * Update Util.js * eslint bad :D * eslint * polish work with files * fix error and TODOs * clean up code to match with repo code style * update typescript params * Update src/util/Util.js camel Case Co-authored-by: Pedro S. Lopez <pedroslopez@me.com> * Update Util.js * ➖ webp-converter ➕ node-webpmux * Update Util.js * ✨ Use node-webpmux * ➖ node-webpmux ➕ node-webpmux-commonjs * ✏️ Fixed require mode * :heavy_plus_sign:node-webpmux ➖ node-webpmux-commonjs * ⬆️ Node-webpmux update changes * 🚨 removing try/catch * 🚨 complier warnings * 🧐 stupid mistakes * ⬆️ Upgrade required version * 🐛 creating a buffer the right way * 🐛 linting and simplification * 🐛 unsimplification * 🚨 eslint loves singlequotes * ✨ Added emojis / categories in metadata * 🏷️ TypeScript Declarations * ✨ Sticker Categories in sendMessage * 🏷️ Improved TS declarations * fix stickerCategories type * fix: don't set name/author if not defined Co-authored-by: Marcelo Carvalho <mpirescarvalho17@gmail.com> Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com> Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
This commit is contained in:
6
index.d.ts
vendored
6
index.d.ts
vendored
@@ -600,6 +600,12 @@ declare namespace WAWebJS {
|
|||||||
sendSeen?: boolean
|
sendSeen?: boolean
|
||||||
/** Media to be sent */
|
/** Media to be sent */
|
||||||
media?: MessageMedia
|
media?: MessageMedia
|
||||||
|
/** Sticker name, if sendMediaAsSticker is true */
|
||||||
|
stickerName?: string
|
||||||
|
/** Sticker author, if sendMediaAsSticker is true */
|
||||||
|
stickerAuthor?: string
|
||||||
|
/** Sticker categories, if sendMediaAsSticker is true */
|
||||||
|
stickerCategories?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Media attached to a message */
|
/** Media attached to a message */
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"jsqr": "^1.3.1",
|
"jsqr": "^1.3.1",
|
||||||
"mime": "^2.4.5",
|
"mime": "^2.4.5",
|
||||||
|
"node-webpmux":"^2.0.0",
|
||||||
"puppeteer": "^5.2.1",
|
"puppeteer": "^5.2.1",
|
||||||
"sharp": "^0.26.3"
|
"sharp": "^0.26.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -437,6 +437,9 @@ class Client extends EventEmitter {
|
|||||||
* @property {string} [quotedMessageId] - Id of the message that is being quoted (or replied to)
|
* @property {string} [quotedMessageId] - Id of the message that is being quoted (or replied to)
|
||||||
* @property {Contact[]} [mentions] - Contacts that are being mentioned in the message
|
* @property {Contact[]} [mentions] - Contacts that are being mentioned in the message
|
||||||
* @property {boolean} [sendSeen=true] - Mark the conversation as seen after sending the message
|
* @property {boolean} [sendSeen=true] - Mark the conversation as seen after sending the message
|
||||||
|
* @property {string} [stickerAuthor=undefined] - Sets the author of the sticker, (if sendMediaAsSticker is true).
|
||||||
|
* @property {string} [stickerName=undefined] - Sets the name of the sticker, (if sendMediaAsSticker is true).
|
||||||
|
* @property {string[]} [stickerCategories=undefined] - Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.
|
||||||
* @property {MessageMedia} [media] - Media to be sent
|
* @property {MessageMedia} [media] - Media to be sent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -481,7 +484,12 @@ class Client extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (internalOptions.sendMediaAsSticker && internalOptions.attachment) {
|
if (internalOptions.sendMediaAsSticker && internalOptions.attachment) {
|
||||||
internalOptions.attachment = await Util.formatToWebpSticker(internalOptions.attachment);
|
internalOptions.attachment =
|
||||||
|
await Util.formatToWebpSticker(internalOptions.attachment, {
|
||||||
|
name: options.stickerName,
|
||||||
|
author: options.stickerAuthor,
|
||||||
|
categories: options.stickerCategories
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => {
|
const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const path = require('path');
|
|||||||
const Crypto = require('crypto');
|
const Crypto = require('crypto');
|
||||||
const { tmpdir } = require('os');
|
const { tmpdir } = require('os');
|
||||||
const ffmpeg = require('fluent-ffmpeg');
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
|
const webp = require('node-webpmux');
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
|
|
||||||
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
||||||
@@ -18,6 +19,16 @@ class Util {
|
|||||||
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static generateHash(length) {
|
||||||
|
var result = '';
|
||||||
|
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
var charactersLength = characters.length;
|
||||||
|
for ( var i = 0; i < length; i++ ) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets default properties on an object that aren't already specified.
|
* Sets default properties on an object that aren't already specified.
|
||||||
* @param {Object} def Default properties
|
* @param {Object} def Default properties
|
||||||
@@ -135,16 +146,49 @@ class Util {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sticker metadata.
|
||||||
|
* @typedef {Object} StickerMetadata
|
||||||
|
* @property {string} [name]
|
||||||
|
* @property {string} [author]
|
||||||
|
* @property {string[]} [categories]
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a media to webp
|
* Formats a media to webp
|
||||||
* @param {MessageMedia} media
|
* @param {MessageMedia} media
|
||||||
|
* @param {StickerMetadata} metadata
|
||||||
*
|
*
|
||||||
* @returns {Promise<MessageMedia>} media in webp format
|
* @returns {Promise<MessageMedia>} media in webp format
|
||||||
*/
|
*/
|
||||||
static async formatToWebpSticker(media) {
|
static async formatToWebpSticker(media, metadata) {
|
||||||
if (media.mimetype.includes('image')) return this.formatImageToWebpSticker(media);
|
let webpMedia;
|
||||||
else if (media.mimetype.includes('video')) return this.formatVideoToWebpSticker(media);
|
|
||||||
else throw new Error('Invalid media format');
|
if (media.mimetype.includes('image'))
|
||||||
|
webpMedia = await this.formatImageToWebpSticker(media);
|
||||||
|
else if (media.mimetype.includes('video'))
|
||||||
|
webpMedia = await this.formatVideoToWebpSticker(media);
|
||||||
|
else
|
||||||
|
throw new Error('Invalid media format');
|
||||||
|
|
||||||
|
if (metadata.name || metadata.author) {
|
||||||
|
const img = new webp.Image();
|
||||||
|
const hash = this.generateHash(32);
|
||||||
|
const stickerPackId = hash;
|
||||||
|
const packname = metadata.name;
|
||||||
|
const author = metadata.author;
|
||||||
|
const categories = metadata.categories || [''];
|
||||||
|
const json = { 'sticker-pack-id': stickerPackId, 'sticker-pack-name': packname, 'sticker-pack-publisher': author, 'emojis': categories };
|
||||||
|
let exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
|
||||||
|
let jsonBuffer = Buffer.from(JSON.stringify(json), 'utf8');
|
||||||
|
let exif = Buffer.concat([exifAttr, jsonBuffer]);
|
||||||
|
exif.writeUIntLE(jsonBuffer.length, 14, 4);
|
||||||
|
await img.loadBuffer(Buffer.from(webpMedia.data, 'base64'));
|
||||||
|
img.exif = exif;
|
||||||
|
webpMedia.data = (await img.saveBuffer()).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
return webpMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,4 +200,4 @@ class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Util;
|
module.exports = Util;
|
||||||
|
|||||||
Reference in New Issue
Block a user