Skip to content

Commit

Permalink
WhatsBot(bfea74f5675941e2b5f15e3a9badffb8788ef1b9)
Browse files Browse the repository at this point in the history
  • Loading branch information
cstayyab committed Jul 11, 2020
1 parent 82d5334 commit e678dae
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 55 deletions.
2 changes: 1 addition & 1 deletion WhatsBot/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module.exports = {
Client: require('./src/Client'),

version: "1.5.1-post",
version: "1.7.0-post",

// Structures
Chat: require('./src/structures/Chat'),
Expand Down
89 changes: 62 additions & 27 deletions WhatsBot/src/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ const puppeteer = require('puppeteer-core');
const moduleRaid = require('@pedroslopez/moduleraid/moduleraid');

const Util = require('./util/Util');
const { WhatsWebURL, UserAgent, DefaultOptions, Events, WAState } = require('./util/Constants');
const InterfaceController = require('./util/InterfaceController');
const { WhatsWebURL, DefaultOptions, Events, WAState } = require('./util/Constants');
const { ExposeStore, LoadUtils } = require('./util/Injected');
const ChatFactory = require('./factories/ChatFactory');
const ContactFactory = require('./factories/ContactFactory');
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification } = require('./structures');
/**
* Starting point for interacting with the WhatsApp Web API
* @extends {EventEmitter}
* @param {object} options
* @fires Client#qr
* @fires Client#authenticated
* @fires Client#auth_failure
Expand Down Expand Up @@ -84,6 +86,9 @@ class Client extends EventEmitter {
return window.Store.Conn.serialize();
}));

// Add InterfaceController
this.interface = new InterfaceController(this);

// Register events
await page.exposeFunction('onAddMessageEvent', msg => {
if (!msg.isNewMsg) return;
Expand Down Expand Up @@ -273,13 +278,22 @@ class Client extends EventEmitter {
*/
async destroy() {
//await this.pupBrowser.close();
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-asset-intro-image="true"]';
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]';
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
}

/**
* Logs out the client, closing the current session
*/
async logout() {
return await this.pupPage.evaluate(() => {
return window.Store.AppState.logout();
});
}

/**
* Returns the version of WhatsApp Web currently being run
* @returns Promise<string>
* @returns {Promise<string>}
*/
async getWWebVersion() {
return await this.pupPage.evaluate(() => {
Expand Down Expand Up @@ -324,38 +338,21 @@ class Client extends EventEmitter {
} else if (options.media instanceof MessageMedia) {
internalOptions.attachment = options.media;
internalOptions.caption = content;
content = '';
} else if (content instanceof Location) {
internalOptions.location = content;
content = '';
}

const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => {
let chat = window.Store.Chat.get(chatId);
let msg;
if (!chat) { // The chat is not available in the previously chatted list

let newChatId = await window.WWebJS.getNumberId(chatId);
if (newChatId) {
//get the topmost chat object and assign the new chatId to it .
//This is just a workaround.May cause problem if there are no chats at all. Need to dig in and emulate how whatsapp web does
let chat = window.Store.Chat.models[0];
if (!chat)
throw 'Chat List empty! Need at least one open conversation with any of your contact';

let originalChatObjId = chat.id;
chat.id = newChatId;

msg = await window.WWebJS.sendMessage(chat, message, options);
chat.id = originalChatObjId; //replace the chat with its original id
}
}
else {
if (sendSeen) {
window.WWebJS.sendSeen(chatId);
}
const chatWid = window.Store.WidFactory.createWid(chatId);
const chat = await window.Store.Chat.find(chatWid);

msg = await window.WWebJS.sendMessage(chat, message, options, sendSeen);
if(sendSeen) {
window.WWebJS.sendSeen(chatId);
}

const msg = await window.WWebJS.sendMessage(chat, message, options, sendSeen);
return msg.serialize();
}, chatId, content, internalOptions, sendSeen);

Expand Down Expand Up @@ -412,6 +409,19 @@ class Client extends EventEmitter {
return ContactFactory.create(this, contact);
}

/**
* Returns an object with information about the invite code's group
* @param {string} inviteCode
* @returns {Promise<object>} Invite information
*/
async getInviteInfo(inviteCode) {
return await this.pupPage.evaluate(inviteCode => {
return window.Store.Wap.groupInviteInfo(inviteCode);
}, inviteCode);
}



/**
* Accepts an invitation to join a group
* @param {string} inviteCode Invitation code
Expand Down Expand Up @@ -476,6 +486,30 @@ class Client extends EventEmitter {
return chat.archive;
}, chatId);
}

/**
* Mutes the Chat until a specified date
* @param {string} chatId ID of the chat that will be muted
* @param {Date} unmuteDate Date when the chat will be unmuted
*/
async muteChat(chatId, unmuteDate) {
await this.pupPage.evaluate(async (chatId, timestamp) => {
let chat = await window.Store.Chat.get(chatId);
await chat.mute.mute(timestamp, !0);
}, chatId, unmuteDate.getTime() / 1000);
}

/**
* Unmutes the Chat
* @param {string} chatId ID of the chat that will be unmuted
*/
async unmuteChat(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.muteChat(chat, false);
}, chatId);
}

/**
* Returns the contact ID's profile picture URL, if privacy settings allow it
* @param {string} contactId the whatsapp user's ID
Expand All @@ -500,6 +534,7 @@ class Client extends EventEmitter {

/**
* Check if a given ID is registered in whatsapp
* @param {string} id the whatsapp user's ID
* @returns {Promise<Boolean>}
*/
async isRegisteredUser(id) {
Expand Down
15 changes: 15 additions & 0 deletions WhatsBot/src/structures/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ class Chat extends Base {
return this.client.unarchiveChat(this.id._serialized);
}

/**
* Mutes this chat until a specified date
* @param {Date} unmuteDate Date at which the Chat will be unmuted
*/
async mute(unmuteDate) {
return this.client.muteChat(this.id._serialized, unmuteDate);
}

/**
* Unmutes this chat
*/
async unmute() {
return this.client.unmuteChat(this.id._serialized);
}

/**
* Loads chat messages, sorted from earliest to latest.
* @param {Object} searchOptions Options for searching messages. Right now only limit is supported.
Expand Down
13 changes: 13 additions & 0 deletions WhatsBot/src/structures/ClientInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ class ClientInfo extends Base {
return super._patch(data);
}

/**
* Get current battery percentage and charging status for the attached device
* @returns {object} batteryStatus
* @returns {number} batteryStatus.battery - The current battery percentage
* @returns {boolean} batteryStatus.plugged - Indicates if the phone is plugged in (true) or not (false)
*/
async getBatteryStatus() {
return await this.client.pupPage.evaluate(() => {
const { battery, plugged } = window.Store.Conn;
return { battery, plugged };
});
}

}

module.exports = ClientInfo;
20 changes: 0 additions & 20 deletions WhatsBot/src/structures/GroupChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,26 +136,6 @@ class GroupChat extends Chat {
}, this.id._serialized);
}

/**
* Returns an object with information about the invite code's group
* @param {string} inviteCode
* @returns {Promise<object>} Invite information
*/
static async getInviteInfo(inviteCode) {
return await this.client.pupPage.evaluate(inviteCode => {
return window.Store.Wap.groupInviteInfo(inviteCode);
}, inviteCode);
}

/**
* Joins a group with an invite code
* @param {string} inviteCode
*/
static async join(inviteCode) {
return await this.client.pupPage.evaluate(inviteCode => {
return window.Store.Wap.acceptGroupInvite(inviteCode);
}, inviteCode);
}

/**
* Makes the bot leave the group
Expand Down
7 changes: 3 additions & 4 deletions WhatsBot/src/structures/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Message extends Base {
* ID for the Chat that this message was sent to, except if the message was sent by the current user.
* @type {string}
*/
this.from = typeof (data.from) === 'object' ? data.from._serialized : data.from;
this.from = (typeof (data.from) === 'object' && data.from !== null) ? data.from._serialized : data.from;

/**
* ID for who this message is for.
Expand All @@ -73,14 +73,13 @@ class Message extends Base {
* If the message is sent by another user, it will be the ID for the current user.
* @type {string}
*/
this.to = typeof (data.to) === 'object' ? data.to._serialized : data.to;
this.to = (typeof (data.to) === 'object' && data.to !== null) ? data.to._serialized : data.to;

/**
* If the message was sent to a group, this field will contain the user that sent the message.
* @type {string}
*/
this.author = typeof (data.author) === 'object' ? data.author._serialized : data.author;

this.author = (typeof (data.author) === 'object' && data.author !== null) ? data.author._serialized : data.author;
/**
* Indicates if the message was forwarded
* @type {boolean}
Expand Down
16 changes: 16 additions & 0 deletions WhatsBot/src/structures/MessageMedia.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
'use strict';

const fs = require('fs');
const path = require('path');
const mime = require('mime');

/**
* Media attached to a message
* @param {string} mimetype MIME type of the attachment
Expand All @@ -26,6 +30,18 @@ class MessageMedia {
*/
this.filename = filename;
}
/**
* Creates a MessageMedia instance from a local file path
* @param {string} filePath
* @returns {MessageMedia}
*/
static fromFilePath(filePath) {
const b64data = fs.readFileSync(filePath, {encoding: 'base64'});
const mimetype = mime.getType(filePath);
const filename = path.basename(filePath);

return new MessageMedia(mimetype, b64data, filename);
}
}

module.exports = MessageMedia;
5 changes: 2 additions & 3 deletions WhatsBot/src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

exports.WhatsWebURL = 'https://web.whatsapp.com/';

exports.UserAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36';

exports.DefaultOptions = {
puppeteer: {
headless: true,
Expand All @@ -14,7 +12,8 @@ exports.DefaultOptions = {
qrRefreshIntervalMs: 20000,
authTimeoutMs: 45000,
takeoverOnConflict: false,
takeoverTimeoutMs: 0
takeoverTimeoutMs: 0,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
};

/**
Expand Down
2 changes: 2 additions & 0 deletions WhatsBot/src/util/Injected.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ exports.ExposeStore = (moduleRaidStr) => {
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default;
window.Store.Validators = window.mR.findModule('findLinks')[0];
window.Store.WidFactory = window.mR.findModule('createWid')[0];
};

exports.LoadUtils = () => {
Expand All @@ -49,6 +50,7 @@ exports.LoadUtils = () => {
let attOptions = {};
if (options.attachment) {
attOptions = await window.WWebJS.processMediaData(options.attachment, options.sendAudioAsVoice);
content = attOptions.preview;
delete options.attachment;
}

Expand Down
56 changes: 56 additions & 0 deletions WhatsBot/src/util/InterfaceController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';

/**
* Interface Controller
*/
class InterfaceController {

constructor(props) {
this.pupPage = props.pupPage;
}

/**
* Opens the Chat Window
* @param {string} chatId ID of the chat window that will be opened
*/
async openChatWindow(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.openChatAt(chat);
}, chatId);
}

/**
* Opens the Chat Drawer
* @param {string} chatId ID of the chat drawer that will be opened
*/
async openChatDrawer(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.chatInfoDrawer(chat);
}, chatId);
}

/**
* Opens the Message Drawer
* @param {string} msgId ID of the message drawer that will be opened
*/
async openMessageDrawer(msgId) {
await this.pupPage.evaluate(async msgId => {
let msg = await window.Store.Msg.get(msgId);
await window.Store.Cmd.msgInfoDrawer(msg);
}, msgId);
}

/**
* Closes the Right Drawer
*/
async closeRightDrawer() {
await this.pupPage.evaluate(async () => {
await window.Store.Cmd.closeDrawerRight();
});
}

}

module.exports = InterfaceController;

0 comments on commit e678dae

Please sign in to comment.