Feat: change profile/group picture (#1916)

* feat: pfp

* Make eslint happy

* Fix typo

* Fix missing comma

* Update src/util/Injected.js

* ESLint

* Update src/util/Injected.js

* mfw purp breaks indentation

---------

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
This commit is contained in:
Wictor Nogueira
2023-03-31 22:21:09 -03:00
committed by GitHub
parent 4846625119
commit dc16bbbdac
4 changed files with 131 additions and 1 deletions

View File

@@ -1178,6 +1178,31 @@ class Client extends EventEmitter {
return blockedContacts.map(contact => ContactFactory.create(this.client, contact));
}
/**
* Sets the current user's profile picture.
* @param {MessageMedia} media
* @returns {Promise<boolean>} Returns true if the picture was properly updated.
*/
async setProfilePicture(media) {
const success = await this.pupPage.evaluate((chatid, media) => {
return window.WWebJS.setPicture(chatid, media);
}, this.info.wid._serialized, media);
return success;
}
/**
* Deletes the current user's profile picture.
* @returns {Promise<boolean>} Returns true if the picture was properly deleted.
*/
async deleteProfilePicture() {
const success = await this.pupPage.evaluate((chatid) => {
return window.WWebJS.deletePicture(chatid);
}, this.info.wid._serialized);
return success;
}
}
module.exports = Client;

View File

@@ -213,6 +213,31 @@ class GroupChat extends Chat {
return true;
}
/**
* Deletes the group's picture.
* @returns {Promise<boolean>} Returns true if the picture was properly deleted. This can return false if the user does not have the necessary permissions.
*/
async deletePicture() {
const success = await this.client.pupPage.evaluate((chatid) => {
return window.WWebJS.deletePicture(chatid);
}, this.id._serialized);
return success;
}
/**
* Sets the group's picture.
* @param {MessageMedia} media
* @returns {Promise<boolean>} Returns true if the picture was properly updated. This can return false if the user does not have the necessary permissions.
*/
async setPicture(media) {
const success = await this.client.pupPage.evaluate((chatid, media) => {
return window.WWebJS.setPicture(chatid, media);
}, this.id._serialized, media);
return success;
}
/**
* Gets the invite code for a specific group
* @returns {Promise<string>} Group's invite code

View File

@@ -62,7 +62,8 @@ exports.ExposeStore = (moduleRaidStr) => {
window.Store.GroupUtils = {
...window.mR.findModule('createGroup')[0],
...window.mR.findModule('setGroupDescription')[0],
...window.mR.findModule('sendExitGroup')[0]
...window.mR.findModule('sendExitGroup')[0],
...window.mR.findModule('sendSetPicture')[0]
};
if (!window.Store.Chat._find) {
@@ -625,4 +626,73 @@ exports.LoadUtils = () => {
]);
await window.Store.Socket.deprecatedCastStanza(stanza);
};
window.WWebJS.cropAndResizeImage = async (media, options = {}) => {
if (!media.mimetype.includes('image'))
throw new Error('Media is not an image');
if (options.mimetype && !options.mimetype.includes('image'))
delete options.mimetype;
options = Object.assign({ size: 640, mimetype: media.mimetype, quality: .75, asDataUrl: false }, options);
const img = await new Promise ((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = `data:${media.mimetype};base64,${media.data}`;
});
const sl = Math.min(img.width, img.height);
const sx = Math.floor((img.width - sl) / 2);
const sy = Math.floor((img.height - sl) / 2);
const canvas = document.createElement('canvas');
canvas.width = options.size;
canvas.height = options.size;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, sx, sy, sl, sl, 0, 0, options.size, options.size);
const dataUrl = canvas.toDataURL(options.mimetype, options.quality);
if (options.asDataUrl)
return dataUrl;
return Object.assign(media, {
mimetype: options.mimeType,
data: dataUrl.replace(`data:${options.mimeType};base64,`, '')
});
};
window.WWebJS.setPicture = async (chatid, media) => {
const thumbnail = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 96 });
const profilePic = await window.WWebJS.cropAndResizeImage(media, { asDataUrl: true, mimetype: 'image/jpeg', size: 640 });
const chatWid = window.Store.WidFactory.createWid(chatid);
try {
const collection = window.Store.ProfilePicThumb.get(chatid);
if (!collection.canSet()) return;
const res = await window.Store.GroupUtils.sendSetPicture(chatWid, thumbnail, profilePic);
return res ? res.status === 200 : false;
} catch (err) {
if(err.name === 'ServerStatusCodeError') return false;
throw err;
}
};
window.WWebJS.deletePicture = async (chatid) => {
const chatWid = window.Store.WidFactory.createWid(chatid);
try {
const collection = window.Store.ProfilePicThumb.get(chatid);
if (!collection.canDelete()) return;
const res = await window.Store.GroupUtils.requestDeletePicture(chatWid);
return res ? res.status === 200 : false;
} catch (err) {
if(err.name === 'ServerStatusCodeError') return false;
throw err;
}
};
};