Skip to content
This repository has been archived by the owner on Feb 5, 2024. It is now read-only.

Commit

Permalink
Add support for sticker Name and author (pedroslopez#527)
Browse files Browse the repository at this point in the history
* 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

* ➕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>
  • Loading branch information
4 people committed May 31, 2021
1 parent 23b5fe1 commit 5c431d8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 6 deletions.
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,12 @@ declare namespace WAWebJS {
sendSeen?: boolean
/** Media to be sent */
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 */
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"fluent-ffmpeg": "^2.1.2",
"jsqr": "^1.3.1",
"mime": "^2.4.5",
"node-webpmux":"^2.0.0",
"puppeteer": "^5.2.1",
"sharp": "^0.26.3"
},
Expand Down
10 changes: 9 additions & 1 deletion src/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ class Client extends EventEmitter {
* @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 {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
*/

Expand Down Expand Up @@ -481,7 +484,12 @@ class Client extends EventEmitter {
}

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) => {
Expand Down
54 changes: 49 additions & 5 deletions src/util/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const path = require('path');
const Crypto = require('crypto');
const { tmpdir } = require('os');
const ffmpeg = require('fluent-ffmpeg');
const webp = require('node-webpmux');
const fs = require('fs').promises;

const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
Expand All @@ -18,6 +19,16 @@ class Util {
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.
* @param {Object} def Default properties
Expand Down Expand Up @@ -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
* @param {MessageMedia} media
* @param {StickerMetadata} metadata
*
* @returns {Promise<MessageMedia>} media in webp format
*/
static async formatToWebpSticker(media) {
if (media.mimetype.includes('image')) return this.formatImageToWebpSticker(media);
else if (media.mimetype.includes('video')) return this.formatVideoToWebpSticker(media);
else throw new Error('Invalid media format');
static async formatToWebpSticker(media, metadata) {
let webpMedia;

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;
}

/**
Expand All @@ -156,4 +200,4 @@ class Util {
}
}

module.exports = Util;
module.exports = Util;

0 comments on commit 5c431d8

Please sign in to comment.