Last active
April 30, 2024 12:05
-
-
Save brkphp/18563307eaa56bce598e2528a0a50180 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// console.log('OKEY'); | |
function getQR() { | |
var qr = document.getElementsByTagName("canvas")[0]; | |
return {connection: document.getElementsByTagName("canvas")[0] == null, qr: qr ? qr.toDataURL() : ""}; | |
} | |
/* | |
export async function loadAllEarlierMessages(id, done) { | |
const found = WAPI.getChat(id); | |
while (!found.msgs.msgLoadState.noEarlierMsgs) { | |
console.log('Loading...'); | |
await found.loadEarlierMsgs(); | |
} | |
} | |
*/ | |
async function getChats(user) { | |
var chats = []; | |
try { | |
for (var chat of window.Store.Chat._models) { | |
if (chat.__x_id._serialized == user) { | |
if (chat.loadEarlierMsgs && !chat.msgs?.msgLoadState?.noEarlierMsgs) { | |
await chat.loadEarlierMsgs(); | |
} | |
for (var msg of chat.msgs._models) { | |
if (msg.__x_type && msg.__x_type != "gp2") { | |
chats.push({ msg: msg.__x_body, type: (msg.__x_type == "ptt") ? "audio" : msg.__x_type, me: msg.__x_isSentByMe /*, n: msg.__x_isNewMsg, t: msg.__x_t*/ }); | |
} | |
} | |
break; | |
} | |
} | |
} catch (e) { | |
console.log(e); | |
} | |
alert(JSON.stringify({ command: "get_chats", chats: chats, connection: document.getElementsByTagName("canvas")[0] == null })); | |
//return { chats: chats, connection: document.getElementsByTagName("canvas")[0] == null}; | |
} | |
function runGetChats(user) { | |
getChats(user) | |
} | |
async function fetcher(path) { | |
let response = await fetch(path); | |
let result = await response.body.getReader().read(); | |
return btoa(String.fromCharCode.apply(null, result.value)); | |
} | |
/*function sleep(milliseconds) { | |
return new Promise(resolve => setTimeout(resolve, milliseconds)) | |
} | |
async function getNextProfilePic(lastUser) { | |
try { | |
for (var chat of window.Store.Chat._models) { | |
if (lastUser != "" && chat.__x_id && (chat.__x_id._serialized != lastUser)) | |
continue; | |
if (chat.__x_id._serialized == lastUser) { | |
lastUser = ""; | |
continue; | |
} | |
var last_msg = (chat.msgs && chat.msgs._models && (chat.msgs._models.length > 0)) ? chat.msgs._models[chat.msgs._models.length - 1] : {}; | |
if (!last_msg.__x_type || last_msg.__x_type == "gp2" || !chat.__x_contact.__x_profilePicThumb || !chat.__x_contact.__x_profilePicThumb.__x_img) | |
continue; | |
for (var contact of lastContacts) { | |
if (contact["u"] == chat.__x_id._serialized) { | |
let image = await fetcher(chat.__x_contact.__x_profilePicThumb.__x_img); | |
if (image && image != "") { | |
alert(JSON.stringify([{u: chat.__x_id._serialized, p: image || ""}])); | |
return; | |
} | |
} | |
} | |
} | |
} catch (e) { | |
console.log(e); | |
} | |
} | |
var lastContacts = []; | |
var lastChange = (new Date()).toString(); | |
function getContacts(lastUpdate, lastUserPic) { | |
var contacts = []; | |
var index = 0; | |
try { | |
if (!window.Store || !window.Store.Chat || !window.Store.Chat._models) | |
return { contacts: [], connection: document.getElementsByTagName("canvas")[0] == null, lastChange: lastChange }; | |
for (var chat of window.Store.Chat._models) { | |
if (chat.__x_id._serialized && chat.__x_formattedTitle) { | |
var contact = {u: chat.__x_id._serialized, n: chat.__x_formattedTitle, c: chat.__x_unreadCount + "" }; | |
var last_msg = (chat.msgs && chat.msgs._models && (chat.msgs._models.length > 0)) ? chat.msgs._models[chat.msgs._models.length - 1] : {}; | |
if (last_msg.__x_type && last_msg.__x_type != "gp2") { | |
if (last_msg.__x_type == "chat") | |
contact["m"] = last_msg.__x_body; | |
else | |
contact["m"] = "[" + ((last_msg.__x_type == "ptt") ? "audio" : last_msg.__x_type) + "]"; | |
//try { | |
// if (chat.__x_contact.__x_profilePicThumb.__x_img) | |
// contact["p"] = chat.__x_contact.__x_profilePicThumb.__x_img; | |
// } catch {} | |
contact["t"] = (new Date(last_msg.__x_t * 1000)).toLocaleString(); | |
contacts.push(contact); | |
index++; | |
if (index == 20) | |
break; | |
} | |
} | |
} | |
if (JSON.stringify(contacts) == JSON.stringify(lastContacts) && lastChange == lastUpdate) { | |
contacts = []; | |
getNextProfilePic(lastUserPic); | |
} | |
else if (contacts.length > 0) { | |
lastChange = (new Date()).toString(); | |
lastContacts = contacts; | |
} | |
} catch (e) { | |
console.log(e); | |
} | |
if ((contacts.length == 0) && (document.body.innerText.indexOf("USE HERE") > 0)) | |
location.reload(); | |
return { contacts: contacts || [], connection: document.getElementsByTagName("canvas")[0] == null, lastChange: lastChange }; | |
}*/ | |
function sendMsg(user, message) { | |
try { | |
for (var chat of window.Store.Chat._models) | |
if (chat.__x_id && (chat.__x_id._serialized == user)) | |
return window.Store.SendTextMsgToChat(chat, message); | |
} catch (e) { | |
console.log(e); | |
} | |
} | |
function fixBinary(bin) { | |
var buf = new ArrayBuffer(bin.length); | |
var arr = new Uint8Array(buf); | |
for (var i = 0; i < bin.length; i++) | |
arr[i] = bin.charCodeAt(i); | |
return buf; | |
} | |
/*function base64ToFile(b64Data, filename) { | |
var arr = b64Data.split(','); | |
var mime = arr[0].match(/:(.*?);/)[1]; | |
var bstr = atob(arr[1]); | |
var n = bstr.length; | |
var u8arr = new Uint8Array(n); | |
while (n--) | |
u8arr[n] = bstr.charCodeAt(n); | |
return new File([u8arr], filename, {type: mime}); | |
}*/ | |
function sendMedia(user, b64) { | |
try { | |
for (var chat of window.Store.Chat._models) { | |
if (chat.__x_id._serialized == user) { | |
var type = b64.split(',')[0].split(';')[0].split(':')[1]; | |
var binary = fixBinary(atob(b64.split(',')[1])); | |
var blob = new Blob([binary], {type: type}); | |
//var random_name = Math.random().toString(36).substr(2, 5); | |
var file = new File([blob], "Click to play", { type: type, lastModified: Date.now() }); | |
var mc = new window.Store.MediaCollection(chat); | |
mc.processAttachments([{file: file}, 1], chat, 1).then(() => { | |
//mc._models[0].mediaPrep._mediaData.type = 'ptt'; | |
mc._models[0].sendToChat(chat, { caption: "Sent from Watch Duo for WhatsApp" }); }); | |
/*var mediaBlob = base64ToFile(b64, Math.random().toString(36).substr(2, 5)); | |
var mc = new Store.MediaCollection(); | |
mc.processFiles([mediaBlob], chat, 1).then(() => { | |
mc._models[0].sendToChat(chat, { caption: "Sent by Duo for WhatsApp from my Apple Watch" }); | |
});*/ | |
break; | |
} | |
} | |
} catch (e) { | |
console.log(e); | |
} | |
} | |
function getStore() { | |
try { | |
let two = document.getElementsByClassName("two")[0] | |
if (!two || !two.children[3] || two.children[3].childElementCount < 1) | |
return; | |
window.mR = moduleRaid(); | |
window.Store = (window.mR.findModule((module) => module.default && module.default.Chat && module.default.Msg)[0] || {}).default; | |
window.Store.SendTextMsgToChat = (window.mR.findModule((module) => module && module.sendTextMsgToChat)[0] || {}).sendTextMsgToChat; | |
window.Store.MediaCollection = (window.mR.findModule((module) => module.default && module.default.prototype && module.default.prototype.processAttachments !== undefined)[0] || {}).default; | |
//window.Store.CryptoLib = (window.mR.findModule((module) => module.decryptE2EMedia ? module : null)[0] || {}); | |
window.Store.DownloadManager = (window.mR.findModule((module) => module.DownloadManager ? module : null)[0] || {}).default; | |
} catch(e) { | |
console.log(e); | |
} | |
} | |
function blobToB64(blob) { | |
return new Promise(function(resolve, reject) { | |
let reader = new FileReader(); | |
reader.readAsDataURL(blob); | |
reader.onload = function (e) { | |
resolve(reader.result.substr(reader.result.indexOf(',') + 1)); | |
}; | |
}); | |
} | |
function runGetMedia(user, index) { | |
console.log("getMedia called", user, index); | |
for (var chat of window.Store.Chat._models) { | |
if (chat.__x_id._serialized == user) { | |
getMedia(chat.msgs._models[parseInt(index)], user, index); | |
break | |
} | |
} | |
} | |
//async function getMedia(msg, user, index) { | |
// console.log("getMedia called", msg); | |
// let response = await fetch(msg.__x_deprecatedMms3Url); | |
// let result = await response.arrayBuffer(); | |
// let dec = await Store.CryptoLib.decryptE2EMedia(msg.__x_type, result, msg.__x_mediaKey, "image/jpeg"); | |
// let media = await blobToB64(dec._blob); | |
// alert(JSON.stringify({command: "get_media", media: media, type: msg.__x_mimetype ? msg.__x_mimetype.split("/")[1].split(";")[0] : "", user: user, index: index})); | |
//} | |
function arrayBufferToBase64(arrayBuffer) { | |
let binary = ''; | |
const bytes = new Uint8Array( arrayBuffer ); | |
const len = bytes.byteLength; | |
for (let i = 0; i < len; i++) { | |
binary += String.fromCharCode( bytes[ i ] ); | |
} | |
return window.btoa( binary ); | |
} | |
async function getThumbnail(msg) { | |
const dataDownload = { directPath: msg.directPath, encFilehash: msg.encFilehash, filehash: msg.filehash, mediaKey: msg.mediaKey, type: msg.type, signal: (new AbortController).signal}; | |
const arraybuffer = await Store.DownloadManager.downloadAndDecrypt(dataDownload); | |
const media = arrayBufferToBase64(arraybuffer); | |
} | |
async function getMedia(msg, user, index) { | |
const dataDownload = { directPath: msg.directPath, encFilehash: msg.encFilehash, filehash: msg.filehash, mediaKey: msg.mediaKey, type: msg.type, signal: (new AbortController).signal}; | |
const arraybuffer = await Store.DownloadManager.downloadAndDecrypt(dataDownload); | |
const media = arrayBufferToBase64(arraybuffer); | |
alert(JSON.stringify({command: "get_media", media: media, type: msg.__x_mimetype ? msg.__x_mimetype.split("/")[1].split(";")[0] : "", user: user, index: index})); | |
} | |
async function getRecentMessages(max) { | |
let index = 0; | |
let ret = []; | |
if (!window.Store || !window.Store.Chat || !window.Store.Chat._models) | |
return ret; | |
for (var chat of window.Store.Chat._models) { | |
if (chat.__x_id._serialized && chat.__x_formattedTitle) { | |
var last_msg = (chat.msgs && chat.msgs._models && (chat.msgs._models.length > 0)) ? chat.msgs._models[chat.msgs._models.length - 1] : {}; | |
if (last_msg.__x_type || last_msg.__x_type != "gp2") { | |
var contact = {u: chat.__x_id._serialized, n: chat.__x_formattedTitle, c: chat.__x_unreadCount + "", m: last_msg.__x_body || "", t: last_msg.__x_t ? (new Date(last_msg.__x_t * 1000)).toLocaleString() : ""}; | |
if (last_msg.__x_type && last_msg.__x_type != "chat") | |
contact["m"] = "[" + ((last_msg.__x_type == "ptt") ? "audio" : last_msg.__x_type) + "]"; | |
// let p = Store.ProfilePicThumb.get(chat.contact.id); | |
// if (p && p.__x_img) | |
// contact["p"] = await fetcher(p.__x_img); | |
let p = await Store.ProfilePicThumb.find(chat.contact.id); | |
if (p && p.img) | |
contact["p"] = await fetcher(p.img); | |
//contact["p"] = p?.img | |
ret.push(contact); | |
if (++index == max) | |
break; | |
} | |
} | |
} | |
return ret; | |
} | |
var recentMessages = ""; | |
async function checkMessages() { | |
let newMessages = await getRecentMessages(40); | |
let newMessagesStr = JSON.stringify(newMessages); | |
if (recentMessages != newMessagesStr) { | |
alert(JSON.stringify({ command: "get_contacts", contacts: newMessages, connection: document.getElementsByTagName("canvas")[0] == null })); | |
//alert(newMessagesStr); | |
} | |
recentMessages = newMessagesStr; | |
} | |
function runCheckMessages() { | |
checkMessages(); | |
if (document.getElementsByTagName("canvas")[0] != null) return -1; | |
return document.querySelectorAll('[aria-label*="unread message"]').length; | |
} | |
function checkStatus() { | |
let e = document.getElementsByClassName('landing-main')[0]; | |
if (e && e.nextSibling) | |
e.parentNode.removeChild(e.nextSibling); | |
if (!window.Store || !window.Store.Chat || !window.Store.Chat._models || (window.Store.Chat._models.length <= 0) || window.Store.SendTextMsgToChat == undefined) { | |
getStore(); | |
} | |
if (window.Store && window.Store.Chat && window.Store.Chat._models && (window.Store.Chat._models.length > 0) && window.Store.SendTextMsgToChat !== undefined /*&& window.Store.MediaCollection !== undefined*/) { | |
return 1; | |
} | |
return (document.getElementsByTagName("canvas")[0] == null) ? 0 : -1; | |
// https://github.com/mukulhase/WebWhatsapp-Wrapper | |
} | |
/* moduleRaid v5 | |
* https://github.com/@pedroslopez/moduleRaid | |
*/ | |
const moduleRaid = function () { | |
moduleRaid.mID = Math.random().toString(36).substring(7); | |
moduleRaid.mObj = {}; | |
fillModuleArray = function() { | |
//webpackChunkbuild | |
webpackChunkwhatsapp_web_client.push([ | |
[moduleRaid.mID], {}, function(e) { | |
Object.keys(e.m).forEach(function(mod) { | |
moduleRaid.mObj[mod] = e(mod); | |
}) | |
} | |
]); | |
} | |
fillModuleArray(); | |
get = function get (id) { | |
return moduleRaid.mObj[id] | |
} | |
findModule = function findModule (query) { | |
results = []; | |
modules = Object.keys(moduleRaid.mObj); | |
modules.forEach(function(mKey) { | |
mod = moduleRaid.mObj[mKey]; | |
if (typeof mod !== 'undefined') { | |
if (typeof query === 'string') { | |
if (typeof mod.default === 'object') { | |
for (key in mod.default) { | |
if (key == query) results.push(mod); | |
} | |
} | |
for (key in mod) { | |
if (key == query) results.push(mod); | |
} | |
} else if (typeof query === 'function') { | |
if (query(mod)) { | |
results.push(mod); | |
} | |
} else { | |
throw new TypeError('findModule can only find via string and function, ' + (typeof query) + ' was passed'); | |
} | |
} | |
}) | |
return results; | |
} | |
return { | |
modules: moduleRaid.mObj, | |
constructors: moduleRaid.cArr, | |
findModule: findModule, | |
get: get | |
} | |
} | |
SingleTapDetector = function(element, handler) { | |
this.element = element; | |
this.handler = handler; | |
element.addEventListener('touchstart', this, false); | |
}; | |
SingleTapDetector.prototype.handleEvent = function(event) { | |
switch (event.type) { | |
case 'touchstart': this.onTouchStart(event); break; | |
case 'touchmove': this.onTouchMove(event); break; | |
case 'touchend': this.onTouchEnd(event); break; | |
} | |
}; | |
SingleTapDetector.prototype.onTouchStart = function(event) { | |
this.element.addEventListener('touchend', this, false); | |
document.body.addEventListener('touchmove', this, false); | |
this.startX = this.currentX = event.touches[0].clientX; | |
this.startY = this.currentY = event.touches[0].clientY; | |
this.startTime = new Date().getTime(); | |
}; | |
SingleTapDetector.prototype.onTouchMove = function(event) { | |
this.currentX = event.touches[0].clientX; | |
this.currentY = event.touches[0].clientY; | |
}; | |
SingleTapDetector.prototype.onTouchEnd = function(event) { | |
var that = this; | |
// Has there been one or more taps in this sequence already? | |
if (this.tapTimer) { | |
// Reset the timer to catch any additional taps in this sequence | |
clearTimeout(this.tapTimer); | |
this.tapTimer = setTimeout(function() { | |
that.tapTimer = null; | |
}, 300); | |
} else { | |
// Make sure the user didn't move too much | |
if (Math.abs(this.currentX - this.startX) < 4 && | |
Math.abs(this.currentY - this.startY) < 4) { | |
// Make sure this isn't a long press | |
if (new Date().getTime() - this.startTime <= 300) { | |
// Make sure this tap wasn't part of a selection event | |
if (window.getSelection() + '' == '') { | |
// Make sure this tap is in fact a single tap | |
this.tapTimer = setTimeout(function() { | |
that.tapTimer = null; | |
// This is a single tap | |
that.handler(event); | |
}, 300); | |
} | |
} | |
} | |
} | |
}; | |
let contacts = null; | |
let lastShowSide = true; | |
function showOne(showSide) { | |
lastShowSide = showSide; | |
let app = document.getElementsByClassName("app-wrapper-web")[0]; | |
if (app) { | |
app.style.overflowX = "hidden"; | |
} | |
let side = document.getElementById("side"); | |
if (side) { | |
side = side.parentElement; | |
if (side) { | |
side.style.flex = "none"; | |
side.style.width = "100vw"; | |
side.style["max-width"] = "100vw"; | |
side.style.display = showSide ? "block": "none"; | |
let main = side.nextSibling; | |
if (main) { | |
main.style.flex = "none"; | |
main.style.width = "100vw"; | |
main.style.display = showSide ? "none" : "block"; | |
if (contacts != document.getElementById("pane-side")) { | |
contacts = document.getElementById("pane-side"); | |
//contacts.addEventListener('click', function(event) { | |
new SingleTapDetector(contacts, function(event) { | |
let hover = event.srcElement || event.target || side.getElementsByClassName("hover")[0] || side.getElementsByClassName("hoverLocal")[0]; | |
console.log(hover); | |
var e = new MouseEvent('mousedown', { 'bubbles': true, 'cancelable': true }); | |
hover.dispatchEvent(e); | |
showOne(false); | |
setTimeout(function() { | |
let header = main.getElementsByTagName("header")[0]; | |
if (header && !document.getElementById("back_link")) { | |
let a = document.createElement("a"); | |
a.id = "back_link"; | |
a.href = '#'; // Güvenli bir yer tutucu olarak kullanın. | |
a.onclick = function() { showOne(true); return false; }; | |
a.innerHTML = "<< "; | |
header.prepend(a); | |
} | |
let down = main.querySelectorAll('[data-icon="down"]')[0]; | |
if (down) { | |
down.click(); | |
} | |
}, 800); | |
}); | |
} | |
} | |
} | |
} | |
} | |
var last_interval = null; | |
var last_qr_url = ""; | |
var last_random = ""; | |
function upload_qr() { | |
if (last_interval) { | |
clearInterval(last_interval); | |
} | |
last_interval = setInterval(function() { | |
let qr = document.getElementsByTagName("canvas")[0]; | |
let qr_url = qr?.toDataURL() | |
if (!qr_url) { | |
clearInterval(last_interval); | |
last_interval = null; | |
} | |
else if (qr_url != last_qr_url) { | |
last_qr_url = qr_url; | |
let put_url = "https://barcode.trackrx.net/barcode/submit-dataurl/" + last_random; | |
alert(JSON.stringify({ command: "upload_barcode", put_url: put_url, qr_url: qr_url})); | |
} | |
}, 500); | |
} | |
function sendQrToAnotherScreen() { | |
alert(JSON.stringify({ command: "send_analytics" })); | |
last_random = Math.random().toString(36).substring(2); | |
upload_qr(); | |
let url = "https://barcode.trackrx.net/barcode/show/" + last_random; | |
let title = "Send and open this web page on another device (30 seconds)"; | |
navigator.share({ title: title, url: url }); | |
return false; | |
} | |
document.addEventListener("visibilitychange", () => { | |
if (!document.hidden && last_interval) { | |
upload_qr(); | |
} | |
}); | |
setInterval(function() { | |
if (document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]') && document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement && document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement.parentElement) { | |
document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement.parentElement.style.transform = "scale(0.8)"; | |
document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement.parentElement.style.width = "95%"; | |
document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement.parentElement.style.minWidth = "0px"; | |
const duoWACode = document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').innerText.replaceAll("-", "").replaceAll("\n", "").trim(); | |
if (window.innerWidth < 700 && duoWACode != "" && !document.getElementById('duoWACode')) { | |
document.querySelector('div[aria-details="link-device-phone-number-code-screen-instructions"]').parentElement.parentElement.innerHTML += "<center><button id='duoWACode' onclick='console.log(\"COPY_LOGIN_CODE=" + duoWACode + "\");' style='font-size: 25px;'>Click to copy code</button><br /><span style='font-size: 25px;'>And paste in WhatsApp</span></center>"; | |
} | |
} | |
if (document.querySelectorAll('[data-icon="back"]').length == 2 && !document.getElementById('download_status')) { | |
const attributeSelector = "src*='blob:https://web.whatsapp.com'"; | |
let imgStatus = document.querySelector(`img[${attributeSelector}]`); | |
let vidStatus = document.querySelector(`video[${attributeSelector}]`); | |
if (imgStatus || vidStatus) { | |
link = document.createElement('a'); | |
link.id = "download_status"; | |
link.style.position = "absolute"; | |
link.style.bottom = "100px"; | |
link.style.zIndex = "999"; | |
link.style.left = "calc(50% - 130px)"; | |
let div = document.createElement("div"); | |
div.appendChild(document.createTextNode("Add to Status Saver tab")); | |
div.style.fontSize = "26px"; | |
div.style.backgroundColor = "white"; | |
link.appendChild(div); | |
let fname = document.querySelector('[data-animate-status-v3-viewer="true"]')?.querySelector('span[dir="auto"]')?.innerText | |
if (!fname) { | |
fname = link.href.split('.com/')[1] | |
} | |
if (vidStatus) { | |
// vidStatus.removeAttribute('autoplay'); | |
// vidStatus.setAttribute('playsinline', 'playsinline'); | |
link.href = vidStatus.getAttribute('src') + "?" + fname; | |
link.download = fname + ".mp4"; | |
vidStatus.parentElement.prepend(link); | |
vidStatus.parentElement.append(link); | |
console.log(link.download); | |
} else { | |
link.href = imgStatus.getAttribute('src') + "?" + fname;; | |
link.download = fname + ".jpeg"; | |
link.href = vidStatus.getAttribute('src') + "?" + fname; | |
imgStatus.parentElement.prepend(link); | |
imgStatus.parentElement.append(link); | |
console.log(vidStatus.parentElement); | |
} | |
} | |
} | |
if (document.getElementsByClassName("landing-headerTitle")[0]) { | |
document.getElementsByClassName("landing-headerTitle")[0].style.display = "none"; | |
document.getElementsByClassName("landing-headerTitle")[0].previousSibling.style.display = "none"; | |
} | |
if (window.innerWidth >= 700) { | |
if (document.getElementsByClassName("landing-title")[0]) { | |
document.getElementsByClassName("landing-title")[0].innerText = "Use WhatsApp on your iPad"; | |
} | |
return; | |
} | |
if (!lastShowSide && document.querySelector("div[data-testid='drawer-middle']") && document.querySelector("div[data-testid='drawer-left']") && document.querySelector("input[type='file']")) { | |
document.querySelector("div[data-testid='drawer-left']").style.display = 'none'; | |
document.querySelector("div[data-testid='drawer-middle']").firstChild.style.width = window.innerWidth + "px"; | |
document.querySelector("input[type='file']").parentElement.style.minWidth = window.innerWidth + "px"; | |
} | |
if (document.querySelector("div[data-testid='drawer-right']")) { | |
document.querySelector("div[data-testid='drawer-right']").style.left = "0px"; | |
document.querySelector("div[data-testid='drawer-right']").style.width = window.innerWidth + "px"; | |
} | |
if (document.querySelector("li[data-testid='mi-close-chat']")) { | |
document.querySelector("li[data-testid='mi-close-chat']").style.display = 'none'; | |
} | |
if (document.querySelector('div[data-animate-modal-popup="true"]')) { | |
document.querySelector('div[data-animate-modal-popup="true"]').style.width = window.innerWidth + "px"; | |
} | |
if (document.querySelector('header[data-testid="chatlist-header"]')) { | |
document.querySelector('header[data-testid="chatlist-header"]').parentElement.style.maxWidth = "100vw"; | |
} | |
if (document.querySelector("div[class='main']") && document.querySelector("div[class='main']").innerText == "WhatsApp") { | |
document.querySelector("div[class='main']").style.display = "none"; | |
} | |
if (document.getElementsByClassName("landing-title")[0]) { | |
document.getElementsByClassName("landing-title")[0].style.margin = "0px"; | |
document.getElementsByClassName("landing-title")[0].style.fontSize = "24px"; | |
document.getElementsByClassName("landing-title")[0].style.fontWeight = "bold"; | |
document.getElementsByClassName("landing-title")[0].style.textAlign = "center"; | |
document.getElementsByClassName("landing-title")[0].innerText = "Dual WhatsApp Guide"; | |
if (document.getElementsByClassName('landing-main')[0]) { | |
document.getElementsByClassName('landing-main')[0].style.paddingTop = "15px"; | |
} | |
if (document.getElementsByClassName("landing-title")[0].nextSibling) { | |
document.getElementsByClassName("landing-title")[0].nextSibling.style.height = "15px"; | |
} | |
// if (document.getElementsByTagName("ol")[0] && !document.getElementById("qr_link")) { | |
// document.getElementsByTagName("ol")[0].firstChild.innerHTML = "Open the official WhatsApp app on another phone or click <a id='qr_link' href='#' onclick='return sendQrToAnotherScreen();'>here</a> to scan the QR using this phone"; | |
// document.getElementsByTagName("ol")[0].lastChild.style.display = "none"; | |
// } | |
} | |
if (document.querySelectorAll('[rel="noopener noreferrer"]')[0]) | |
document.querySelectorAll('[rel="noopener noreferrer"]')[0].style = "display: none"; | |
if (document.getElementsByClassName("landing-wrapper")[0]) | |
document.getElementsByClassName("landing-wrapper")[0].style = "padding: 0px !important; width: 100% !important; min-width: 0px !important; height: 100% !important;"; | |
if (document.getElementsByClassName("landing-header")[0]) | |
document.getElementsByClassName("landing-header")[0].style = "display: none"; | |
// if (document.getElementsByClassName("landing-window")[0]) | |
// document.getElementsByClassName("landing-window")[0].style = "margin-left: 0px !important; margin-right: 0px !important; width: 100% !important; height: 100% !important;"; | |
// | |
if (contacts != document.getElementById("pane-side") && window.innerWidth < 700) { | |
showOne(true); | |
var meta = document.createElement('meta'); | |
meta.name = 'viewport'; | |
meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'; | |
var head = document.getElementsByTagName('head')[0]; | |
head.appendChild(meta); | |
} | |
}, 500); | |
//sendMedia("[email protected]", ""); | |
function triggerMouseEvent(node, eventType) { | |
var clickEvent = document.createEvent("MouseEvents"); | |
clickEvent.initEvent(eventType, true, true); | |
node.dispatchEvent(clickEvent); | |
} | |
function sleep(ms) { | |
return new Promise((res) => setTimeout(res, ms)); | |
} | |
async function markMessageRead(message) { | |
["mouseover", "mousedown", "mouseup", "click"].map((event) => triggerMouseEvent(message, event)); | |
await sleep(1000); | |
} | |
async function markAllRead() { | |
for (const message of document.querySelectorAll('[aria-label*="unread message"]')) { | |
await markMessageRead(message); | |
} | |
await markMessageRead(document.querySelectorAll('[data-icon*="default-user"]')[1]); | |
} | |
function addCss(rule) { | |
let css = document.createElement('style'); | |
css.type = 'text/css'; | |
css.appendChild(document.createTextNode(rule)); | |
document.getElementsByTagName("head")[0].appendChild(css); | |
} | |
let buttonInterval = setInterval(function() { | |
if (document.querySelector('span[role="button"]') && document.getElementsByTagName("canvas")[0]) { | |
clearInterval(buttonInterval); | |
document.querySelector('span[role="button"]').click(); | |
} | |
}, 500); | |
/** | |
* This script contains WAPI functions that need to be run in the context of the webpage | |
*/ | |
/** | |
* Auto discovery the webpack object references of instances that contains all functions used by the WAPI | |
* functions and creates the Store object. | |
*/ | |
if (!window.Store) { | |
(function () { | |
function getStore(modules) { | |
let foundCount = 0; | |
let neededObjects = [ | |
{ id: "Store", conditions: (module) => (module.default && module.default.Chat && module.default.Msg) ? module.default : null }, | |
{ id: "MediaCollection", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.processAttachments) ? module.default : null }, | |
{ id: "MediaProcess", conditions: (module) => (module.BLOB) ? module : null }, | |
{ id: "Wap", conditions: (module) => (module.createGroup) ? module : null }, | |
{ id: "ServiceWorker", conditions: (module) => (module.default && module.default.killServiceWorker) ? module : null }, | |
{ id: "State", conditions: (module) => (module.STATE && module.STREAM) ? module : null }, | |
{ id: "WapDelete", conditions: (module) => (module.sendConversationDelete && module.sendConversationDelete.length == 2) ? module : null }, | |
{ id: "Conn", conditions: (module) => (module.default && module.default.ref && module.default.refTTL) ? module.default : null }, | |
{ id: "WapQuery", conditions: (module) => (module.default && module.default.queryExist) ? module.default : null }, | |
{ id: "CryptoLib", conditions: (module) => (module.decryptE2EMedia) ? module : null }, | |
{ id: "OpenChat", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.openChat) ? module.default : null }, | |
{ id: "UserConstructor", conditions: (module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null }, | |
{ id: "SendTextMsgToChat", conditions: (module) => (module.sendTextMsgToChat) ? module.sendTextMsgToChat : null }, | |
{ id: "SendSeen", conditions: (module) => (module.sendSeen) ? module.sendSeen : null }, | |
{ id: "sendDelete", conditions: (module) => (module.sendDelete) ? module.sendDelete : null } | |
]; | |
for (let idx in modules) { | |
if ((typeof modules[idx] === "object") && (modules[idx] !== null)) { | |
neededObjects.forEach((needObj) => { | |
if (!needObj.conditions || needObj.foundedModule) | |
return; | |
let neededModule = needObj.conditions(modules[idx]); | |
if (neededModule !== null) { | |
foundCount++; | |
needObj.foundedModule = neededModule; | |
} | |
}); | |
if (foundCount == neededObjects.length) { | |
break; | |
} | |
} | |
} | |
let neededStore = neededObjects.find((needObj) => needObj.id === "Store"); | |
window.Store = neededStore.foundedModule ? neededStore.foundedModule : {}; | |
neededObjects.splice(neededObjects.indexOf(neededStore), 1); | |
neededObjects.forEach((needObj) => { | |
if (needObj.foundedModule) { | |
window.Store[needObj.id] = needObj.foundedModule; | |
} | |
}); | |
window.Store.Chat.modelClass.prototype.sendMessage = function (e) { | |
window.Store.SendTextMsgToChat(this, ...arguments); | |
} | |
return window.Store; | |
} | |
if (typeof webpackJsonp === 'function') { | |
webpackJsonp([], {'parasite': (x, y, z) => getStore(z)}, ['parasite']); | |
} else { | |
let tag = new Date().getTime(); | |
webpackChunkwhatsapp_web_client.push([ | |
["parasite" + tag], | |
{ | |
}, | |
function (o, e, t) { | |
let modules = []; | |
for (let idx in o.m) { | |
let module = o(idx); | |
modules.push(module); | |
} | |
getStore(modules); | |
} | |
]); | |
} | |
})(); | |
} | |
window.WAPI = { | |
lastRead: {} | |
}; | |
window.WAPI._serializeRawObj = (obj) => { | |
if (obj) { | |
return obj.toJSON(); | |
} | |
return {} | |
}; | |
/** | |
* Serializes a chat object | |
* | |
* @param rawChat Chat object | |
* @returns {{}} | |
*/ | |
window.WAPI._serializeChatObj = (obj) => { | |
if (obj == undefined) { | |
return null; | |
} | |
return Object.assign(window.WAPI._serializeRawObj(obj), { | |
kind : obj.kind, | |
isGroup : obj.isGroup, | |
contact : obj['contact'] ? window.WAPI._serializeContactObj(obj['contact']) : null, | |
groupMetadata: obj["groupMetadata"] ? window.WAPI._serializeRawObj(obj["groupMetadata"]): null, | |
presence : obj["presence"] ? window.WAPI._serializeRawObj(obj["presence"]) : null, | |
msgs : null | |
}); | |
}; | |
window.WAPI._serializeContactObj = (obj) => { | |
if (obj == undefined) { | |
return null; | |
} | |
return Object.assign(window.WAPI._serializeRawObj(obj), { | |
formattedName : obj.formattedName, | |
isHighLevelVerified: obj.isHighLevelVerified, | |
isMe : obj.isMe, | |
isMyContact : obj.isMyContact, | |
isPSA : obj.isPSA, | |
isUser : obj.isUser, | |
isVerified : obj.isVerified, | |
isWAContact : obj.isWAContact, | |
profilePicThumbObj : obj.profilePicThumb ? WAPI._serializeProfilePicThumb(obj.profilePicThumb): {}, | |
statusMute : obj.statusMute, | |
msgs : null | |
}); | |
}; | |
window.WAPI._serializeMessageObj = (obj) => { | |
if (obj == undefined) { | |
return null; | |
} | |
return Object.assign(window.WAPI._serializeRawObj(obj), { | |
id : obj.id._serialized, | |
sender : obj["senderObj"] ? WAPI._serializeContactObj(obj["senderObj"]): null, | |
timestamp : obj["t"], | |
content : obj["body"], | |
isGroupMsg : obj.isGroupMsg, | |
isLink : obj.isLink, | |
isMMS : obj.isMMS, | |
isMedia : obj.isMedia, | |
isNotification: obj.isNotification, | |
isPSA : obj.isPSA, | |
type : obj.type, | |
chat : WAPI._serializeChatObj(obj['chat']), | |
chatId : obj.id.remote, | |
quotedMsgObj : WAPI._serializeMessageObj(obj['_quotedMsgObj']), | |
mediaData : window.WAPI._serializeRawObj(obj['mediaData']) | |
}); | |
}; | |
window.WAPI._serializeNumberStatusObj = (obj) => { | |
if (obj == undefined) { | |
return null; | |
} | |
return Object.assign({}, { | |
id : obj.jid, | |
status : obj.status, | |
isBusiness : (obj.biz === true), | |
canReceiveMessage: (obj.status === 200) | |
}); | |
}; | |
window.WAPI._serializeProfilePicThumb = (obj) => { | |
if (obj == undefined) { | |
return null; | |
} | |
return Object.assign({}, { | |
eurl : obj.eurl, | |
id : obj.id, | |
img : obj.img, | |
imgFull: obj.imgFull, | |
raw : obj.raw, | |
tag : obj.tag | |
}); | |
} | |
window.WAPI.createGroup = function (name, contactsId) { | |
if (!Array.isArray(contactsId)) { | |
contactsId = [contactsId]; | |
} | |
return window.Store.Wap.createGroup(name, contactsId); | |
}; | |
window.WAPI.leaveGroup = function (groupId) { | |
groupId = typeof groupId == "string" ? groupId : groupId._serialized; | |
var group = WAPI.getChat(groupId); | |
return group.sendExit() | |
}; | |
window.WAPI.getAllContacts = function (done) { | |
const contacts = window.Store.Contact.map((contact) => WAPI._serializeContactObj(contact)); | |
if (done !== undefined) done(contacts); | |
return contacts; | |
}; | |
/** | |
* Fetches all contact objects from store, filters them | |
* | |
* @param done Optional callback function for async execution | |
* @returns {Array|*} List of contacts | |
*/ | |
window.WAPI.getMyContacts = function (done) { | |
const contacts = window.Store.Contact.filter((contact) => contact.isMyContact === true).map((contact) => WAPI._serializeContactObj(contact)); | |
if (done !== undefined) done(contacts); | |
return contacts; | |
}; | |
/** | |
* Fetches contact object from store by ID | |
* | |
* @param id ID of contact | |
* @param done Optional callback function for async execution | |
* @returns {T|*} Contact object | |
*/ | |
window.WAPI.getContact = function (id, done) { | |
const found = window.Store.Contact.get(id); | |
if (done !== undefined) done(window.WAPI._serializeContactObj(found)) | |
return window.WAPI._serializeContactObj(found); | |
}; | |
/** | |
* Fetches all chat objects from store | |
* | |
* @param done Optional callback function for async execution | |
* @returns {Array|*} List of chats | |
*/ | |
window.WAPI.getAllChats = function (done) { | |
const chats = window.Store.Chat.map((chat) => WAPI._serializeChatObj(chat)); | |
if (done !== undefined) done(chats); | |
return chats; | |
}; | |
window.WAPI.haveNewMsg = function (chat) { | |
return chat.unreadCount > 0; | |
}; | |
window.WAPI.getAllChatsWithNewMsg = function (done) { | |
const chats = window.Store.Chat.filter(window.WAPI.haveNewMsg).map((chat) => WAPI._serializeChatObj(chat)); | |
if (done !== undefined) done(chats); | |
return chats; | |
}; | |
/** | |
* Fetches all chat IDs from store | |
* | |
* @param done Optional callback function for async execution | |
* @returns {Array|*} List of chat id's | |
*/ | |
window.WAPI.getAllChatIds = function (done) { | |
const chatIds = window.Store.Chat.map((chat) => chat.id._serialized || chat.id); | |
if (done !== undefined) done(chatIds); | |
return chatIds; | |
}; | |
/** | |
* Fetches all groups objects from store | |
* | |
* @param done Optional callback function for async execution | |
* @returns {Array|*} List of chats | |
*/ | |
window.WAPI.getAllGroups = function (done) { | |
const groups = window.Store.Chat.filter((chat) => chat.isGroup); | |
if (done !== undefined) done(groups); | |
return groups; | |
}; | |
/** | |
* Fetches chat object from store by ID | |
* | |
* @param id ID of chat | |
* @param done Optional callback function for async execution | |
* @returns {T|*} Chat object | |
*/ | |
window.WAPI.getChat = function (id, done) { | |
id = typeof id == "string" ? id : id._serialized; | |
const found = window.Store.Chat.get(id); | |
found.sendMessage = (found.sendMessage) ? found.sendMessage : function () { return window.Store.sendMessage.apply(this, arguments); }; | |
if (done !== undefined) done(found); | |
return found; | |
} | |
window.WAPI.getChatByName = function (name, done) { | |
const found = window.WAPI.getAllChats().find(val => val.name.includes(name)) | |
if (done !== undefined) done(found); | |
return found; | |
}; | |
window.WAPI.sendImageFromDatabasePicBot = function (picId, chatId, caption) { | |
var chatDatabase = window.WAPI.getChatByName('DATABASEPICBOT'); | |
var msgWithImg = chatDatabase.msgs.find((msg) => msg.caption == picId); | |
if (msgWithImg === undefined) { | |
return false; | |
} | |
var chatSend = WAPI.getChat(chatId); | |
if (chatSend === undefined) { | |
return false; | |
} | |
const oldCaption = msgWithImg.caption; | |
msgWithImg.id.id = window.WAPI.getNewId(); | |
msgWithImg.id.remote = chatId; | |
msgWithImg.t = Math.ceil(new Date().getTime() / 1000); | |
msgWithImg.to = chatId; | |
if (caption !== undefined && caption !== '') { | |
msgWithImg.caption = caption; | |
} else { | |
msgWithImg.caption = ''; | |
} | |
msgWithImg.collection.send(msgWithImg).then(function (e) { | |
msgWithImg.caption = oldCaption; | |
}); | |
return true; | |
}; | |
window.WAPI.sendMessageWithThumb = function (thumb, url, title, description, text, chatId, done) { | |
var chatSend = WAPI.getChat(chatId); | |
if (chatSend === undefined) { | |
if (done !== undefined) done(false); | |
return false; | |
} | |
var linkPreview = { | |
canonicalUrl: url, | |
description : description, | |
matchedText : url, | |
title : title, | |
thumbnail : thumb, | |
compose: true | |
}; | |
chatSend.sendMessage(text, { linkPreview: linkPreview, | |
mentionedJidList: [], | |
quotedMsg: null, | |
quotedMsgAdminGroupJid: null }); | |
if (done !== undefined) done(true); | |
return true; | |
}; | |
window.WAPI.getNewId = function () { | |
var text = ""; | |
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |
for (var i = 0; i < 20; i++) | |
text += possible.charAt(Math.floor(Math.random() * possible.length)); | |
return text; | |
}; | |
window.WAPI.getChatById = function (id, done) { | |
let found = WAPI.getChat(id); | |
if (found) { | |
found = WAPI._serializeChatObj(found); | |
} else { | |
found = false; | |
} | |
if (done !== undefined) done(found); | |
return found; | |
}; | |
/** | |
* I return all unread messages from an asked chat and mark them as read. | |
* | |
* :param id: chat id | |
* :type id: string | |
* | |
* :param includeMe: indicates if user messages have to be included | |
* :type includeMe: boolean | |
* | |
* :param includeNotifications: indicates if notifications have to be included | |
* :type includeNotifications: boolean | |
* | |
* :param done: callback passed by selenium | |
* :type done: function | |
* | |
* :returns: list of unread messages from asked chat | |
* :rtype: object | |
*/ | |
window.WAPI.getUnreadMessagesInChat = function (id, includeMe, includeNotifications, done) { | |
// get chat and its messages | |
let chat = WAPI.getChat(id); | |
let messages = chat.msgs._models; | |
// initialize result list | |
let output = []; | |
// look for unread messages, newest is at the end of array | |
for (let i = messages.length - 1; i >= 0; i--) { | |
// system message: skip it | |
if (i === "remove") { | |
continue; | |
} | |
// get message | |
let messageObj = messages[i]; | |
// found a read message: stop looking for others | |
if (typeof (messageObj.isNewMsg) !== "boolean" || messageObj.isNewMsg === false) { | |
continue; | |
} else { | |
messageObj.isNewMsg = false; | |
// process it | |
let message = WAPI.processMessageObj(messageObj, | |
includeMe, | |
includeNotifications); | |
// save processed message on result list | |
if (message) | |
output.push(message); | |
} | |
} | |
// callback was passed: run it | |
if (done !== undefined) done(output); | |
// return result list | |
return output; | |
} | |
; | |
/** | |
* Load more messages in chat object from store by ID | |
* | |
* @param id ID of chat | |
* @param done Optional callback function for async execution | |
* @returns None | |
*/ | |
window.WAPI.loadEarlierMessages = function (id, done) { | |
const found = WAPI.getChat(id); | |
if (done !== undefined) { | |
found.loadEarlierMsgs().then(function () { | |
done() | |
}); | |
} else { | |
found.loadEarlierMsgs(); | |
} | |
}; | |
/** | |
* Load more messages in chat object from store by ID | |
* | |
* @param id ID of chat | |
* @param done Optional callback function for async execution | |
* @returns None | |
*/ | |
window.WAPI.loadAllEarlierMessages = function (id, done) { | |
const found = WAPI.getChat(id); | |
x = function () { | |
if (!found.msgs.msgLoadState.noEarlierMsgs) { | |
found.loadEarlierMsgs().then(x); | |
} else if (done) { | |
done(); | |
} | |
}; | |
x(); | |
}; | |
window.WAPI.asyncLoadAllEarlierMessages = function (id, done) { | |
done(); | |
window.WAPI.loadAllEarlierMessages(id); | |
}; | |
window.WAPI.areAllMessagesLoaded = function (id, done) { | |
const found = WAPI.getChat(id); | |
if (!found.msgs.msgLoadState.noEarlierMsgs) { | |
if (done) done(false); | |
return false | |
} | |
if (done) done(true); | |
return true | |
}; | |
/** | |
* Load more messages in chat object from store by ID till a particular date | |
* | |
* @param id ID of chat | |
* @param lastMessage UTC timestamp of last message to be loaded | |
* @param done Optional callback function for async execution | |
* @returns None | |
*/ | |
window.WAPI.loadEarlierMessagesTillDate = function (id, lastMessage, done) { | |
const found = WAPI.getChat(id); | |
x = function () { | |
if (found.msgs.models[0].t > lastMessage && !found.msgs.msgLoadState.noEarlierMsgs) { | |
found.loadEarlierMsgs().then(x); | |
} else { | |
done(); | |
} | |
}; | |
x(); | |
}; | |
/** | |
* Fetches all group metadata objects from store | |
* | |
* @param done Optional callback function for async execution | |
* @returns {Array|*} List of group metadata | |
*/ | |
window.WAPI.getAllGroupMetadata = function (done) { | |
const groupData = window.Store.GroupMetadata.map((groupData) => groupData.all); | |
if (done !== undefined) done(groupData); | |
return groupData; | |
}; | |
/** | |
* Fetches group metadata object from store by ID | |
* | |
* @param id ID of group | |
* @param done Optional callback function for async execution | |
* @returns {T|*} Group metadata object | |
*/ | |
window.WAPI.getGroupMetadata = async function (id, done) { | |
let output = window.Store.GroupMetadata.get(id); | |
if (output !== undefined) { | |
if (output.stale) { | |
await window.Store.GroupMetadata.update(id); | |
} | |
} | |
if (done !== undefined) done(output); | |
return output; | |
}; | |
/** | |
* Fetches group participants | |
* | |
* @param id ID of group | |
* @returns {Promise.<*>} Yields group metadata | |
* @private | |
*/ | |
window.WAPI._getGroupParticipants = async function (id) { | |
const metadata = await WAPI.getGroupMetadata(id); | |
return metadata.participants; | |
}; | |
/** | |
* Fetches IDs of group participants | |
* | |
* @param id ID of group | |
* @param done Optional callback function for async execution | |
* @returns {Promise.<Array|*>} Yields list of IDs | |
*/ | |
window.WAPI.getGroupParticipantIDs = async function (id, done) { | |
const output = (await WAPI._getGroupParticipants(id)) | |
.map((participant) => participant.id); | |
if (done !== undefined) done(output); | |
return output; | |
}; | |
window.WAPI.getGroupAdmins = async function (id, done) { | |
const output = (await WAPI._getGroupParticipants(id)) | |
.filter((participant) => participant.isAdmin) | |
.map((admin) => admin.id); | |
if (done !== undefined) done(output); | |
return output; | |
}; | |
/** | |
* Gets object representing the logged in user | |
* | |
* @returns {Array|*|$q.all} | |
*/ | |
window.WAPI.getMe = function (done) { | |
const rawMe = window.Store.Contact.get(window.Store.Conn.me); | |
if (done !== undefined) done(rawMe.all); | |
return rawMe.all; | |
}; | |
window.WAPI.isLoggedIn = function (done) { | |
// Contact always exists when logged in | |
const isLogged = window.Store.Contact && window.Store.Contact.checksum !== undefined; | |
if (done !== undefined) done(isLogged); | |
return isLogged; | |
}; | |
window.WAPI.isConnected = function (done) { | |
// Phone Disconnected icon appears when phone is disconnected from the tnternet | |
const isConnected = document.querySelector('*[data-icon="alert-phone"]') !== null ? false : true; | |
if (done !== undefined) done(isConnected); | |
return isConnected; | |
}; | |
window.WAPI.processMessageObj = function (messageObj, includeMe, includeNotifications) { | |
if (messageObj.isNotification) { | |
if (includeNotifications) | |
return WAPI._serializeMessageObj(messageObj); | |
else | |
return; | |
// System message | |
// (i.e. "Messages you send to this chat and calls are now secured with end-to-end encryption...") | |
} else if (messageObj.id.fromMe === false || includeMe) { | |
return WAPI._serializeMessageObj(messageObj); | |
} | |
return; | |
}; | |
window.WAPI.getAllMessagesInChat = function (id, includeMe, includeNotifications, done) { | |
const chat = WAPI.getChat(id); | |
let output = []; | |
const messages = chat.msgs._models; | |
for (const i in messages) { | |
if (i === "remove") { | |
continue; | |
} | |
const messageObj = messages[i]; | |
let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications) | |
if (message) | |
output.push(message); | |
} | |
if (done !== undefined) done(output); | |
return output; | |
}; | |
window.WAPI.getAllMessageIdsInChat = function (id, includeMe, includeNotifications, done) { | |
const chat = WAPI.getChat(id); | |
let output = []; | |
const messages = chat.msgs._models; | |
for (const i in messages) { | |
if ((i === "remove") | |
|| (!includeMe && messages[i].isMe) | |
|| (!includeNotifications && messages[i].isNotification)) { | |
continue; | |
} | |
output.push(messages[i].id._serialized); | |
} | |
if (done !== undefined) done(output); | |
return output; | |
}; | |
window.WAPI.getMessageById = function (id, done) { | |
let result = false; | |
try { | |
let msg = window.Store.Msg.get(id); | |
if (msg) { | |
result = WAPI.processMessageObj(msg, true, true); | |
} | |
} catch (err) { } | |
if (done !== undefined) { | |
done(result); | |
} else { | |
return result; | |
} | |
}; | |
window.WAPI.ReplyMessage = function (idMessage, message, done) { | |
var messageObject = window.Store.Msg.get(idMessage); | |
if (messageObject === undefined) { | |
if (done !== undefined) done(false); | |
return false; | |
} | |
messageObject = messageObject.value(); | |
const chat = WAPI.getChat(messageObject.chat.id) | |
if (chat !== undefined) { | |
if (done !== undefined) { | |
chat.sendMessage(message, null, messageObject).then(function () { | |
function sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
var trials = 0; | |
function check() { | |
for (let i = chat.msgs.models.length - 1; i >= 0; i--) { | |
let msg = chat.msgs.models[i]; | |
if (!msg.senderObj.isMe || msg.body != message) { | |
continue; | |
} | |
done(WAPI._serializeMessageObj(msg)); | |
return True; | |
} | |
trials += 1; | |
console.log(trials); | |
if (trials > 30) { | |
done(true); | |
return; | |
} | |
sleep(500).then(check); | |
} | |
check(); | |
}); | |
return true; | |
} else { | |
chat.sendMessage(message, null, messageObject); | |
return true; | |
} | |
} else { | |
if (done !== undefined) done(false); | |
return false; | |
} | |
}; | |
window.WAPI.sendMessageToID = function (id, message, done) { | |
try { | |
window.getContact = (id) => { | |
return Store.WapQuery.queryExist(id); | |
} | |
window.getContact(id).then(contact => { | |
if (contact.status === 404) { | |
done(true); | |
} else { | |
Store.Chat.find(contact.jid).then(chat => { | |
chat.sendMessage(message); | |
return true; | |
}).catch(reject => { | |
if (WAPI.sendMessage(id, message)) { | |
done(true); | |
return true; | |
}else{ | |
done(false); | |
return false; | |
} | |
}); | |
} | |
}); | |
} catch (e) { | |
if (window.Store.Chat.length === 0) | |
return false; | |
firstChat = Store.Chat.models[0]; | |
var originalID = firstChat.id; | |
firstChat.id = typeof originalID === "string" ? id : new window.Store.UserConstructor(id, { intentionallyUsePrivateConstructor: true }); | |
if (done !== undefined) { | |
firstChat.sendMessage(message).then(function () { | |
firstChat.id = originalID; | |
done(true); | |
}); | |
return true; | |
} else { | |
firstChat.sendMessage(message); | |
firstChat.id = originalID; | |
return true; | |
} | |
} | |
if (done !== undefined) done(false); | |
return false; | |
} | |
window.WAPI.sendMessage = function (id, message, done) { | |
var chat = WAPI.getChat(id); | |
if (chat !== undefined) { | |
if (done !== undefined) { | |
chat.sendMessage(message).then(function () { | |
function sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
var trials = 0; | |
function check() { | |
for (let i = chat.msgs.models.length - 1; i >= 0; i--) { | |
let msg = chat.msgs.models[i]; | |
if (!msg.senderObj.isMe || msg.body != message) { | |
continue; | |
} | |
done(WAPI._serializeMessageObj(msg)); | |
return True; | |
} | |
trials += 1; | |
console.log(trials); | |
if (trials > 30) { | |
done(true); | |
return; | |
} | |
sleep(500).then(check); | |
} | |
check(); | |
}); | |
return true; | |
} else { | |
chat.sendMessage(message); | |
return true; | |
} | |
} else { | |
if (done !== undefined) done(false); | |
return false; | |
} | |
}; | |
window.WAPI.sendMessage2 = function (id, message, done) { | |
var chat = WAPI.getChat(id); | |
if (chat !== undefined) { | |
try { | |
if (done !== undefined) { | |
chat.sendMessage(message).then(function () { | |
done(true); | |
}); | |
} else { | |
chat.sendMessage(message); | |
} | |
return true; | |
} catch (error) { | |
if (done !== undefined) done(false) | |
return false; | |
} | |
} | |
if (done !== undefined) done(false) | |
return false; | |
}; | |
window.WAPI.sendSeen = function (id, done) { | |
var chat = window.WAPI.getChat(id); | |
if (chat !== undefined) { | |
if (done !== undefined) { | |
if (chat.getLastMsgKeyForAction === undefined) | |
chat.getLastMsgKeyForAction = function () { }; | |
Store.SendSeen(chat, false).then(function () { | |
done(true); | |
}); | |
return true; | |
} else { | |
Store.SendSeen(chat, false); | |
return true; | |
} | |
} | |
if (done !== undefined) done(); | |
return false; | |
}; | |
function isChatMessage(message) { | |
if (message.isSentByMe) { | |
return false; | |
} | |
if (message.isNotification) { | |
return false; | |
} | |
if (!message.isUserCreatedType) { | |
return false; | |
} | |
return true; | |
} | |
window.WAPI.getUnreadMessages = function (includeMe, includeNotifications, use_unread_count, done) { | |
const chats = window.Store.Chat.models; | |
let output = []; | |
for (let chat in chats) { | |
if (isNaN(chat)) { | |
continue; | |
} | |
let messageGroupObj = chats[chat]; | |
let messageGroup = WAPI._serializeChatObj(messageGroupObj); | |
messageGroup.messages = []; | |
const messages = messageGroupObj.msgs._models; | |
for (let i = messages.length - 1; i >= 0; i--) { | |
let messageObj = messages[i]; | |
if (typeof (messageObj.isNewMsg) != "boolean" || messageObj.isNewMsg === false) { | |
continue; | |
} else { | |
messageObj.isNewMsg = false; | |
let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); | |
if (message) { | |
messageGroup.messages.push(message); | |
} | |
} | |
} | |
if (messageGroup.messages.length > 0) { | |
output.push(messageGroup); | |
} else { // no messages with isNewMsg true | |
if (use_unread_count) { | |
let n = messageGroupObj.unreadCount; // will use unreadCount attribute to fetch last n messages from sender | |
for (let i = messages.length - 1; i >= 0; i--) { | |
let messageObj = messages[i]; | |
if (n > 0) { | |
if (!messageObj.isSentByMe) { | |
let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); | |
messageGroup.messages.unshift(message); | |
n -= 1; | |
} | |
} else if (n === -1) { // chat was marked as unread so will fetch last message as unread | |
if (!messageObj.isSentByMe) { | |
let message = WAPI.processMessageObj(messageObj, includeMe, includeNotifications); | |
messageGroup.messages.unshift(message); | |
break; | |
} | |
} else { // unreadCount = 0 | |
break; | |
} | |
} | |
if (messageGroup.messages.length > 0) { | |
messageGroupObj.unreadCount = 0; // reset unread counter | |
output.push(messageGroup); | |
} | |
} | |
} | |
} | |
if (done !== undefined) { | |
done(output); | |
} | |
return output; | |
}; | |
window.WAPI.getGroupOwnerID = async function (id, done) { | |
const output = (await WAPI.getGroupMetadata(id)).owner.id; | |
if (done !== undefined) { | |
done(output); | |
} | |
return output; | |
}; | |
window.WAPI.getCommonGroups = async function (id, done) { | |
let output = []; | |
groups = window.WAPI.getAllGroups(); | |
for (let idx in groups) { | |
try { | |
participants = await window.WAPI.getGroupParticipantIDs(groups[idx].id); | |
if (participants.filter((participant) => participant == id).length) { | |
output.push(groups[idx]); | |
} | |
} catch (err) { | |
console.log("Error in group:"); | |
console.log(groups[idx]); | |
console.log(err); | |
} | |
} | |
if (done !== undefined) { | |
done(output); | |
} | |
return output; | |
}; | |
window.WAPI.getProfilePicSmallFromId = function (id, done) { | |
window.Store.ProfilePicThumb.find(id).then(function (d) { | |
if (d.img !== undefined) { | |
window.WAPI.downloadFileWithCredentials(d.img, done); | |
} else { | |
done(false); | |
} | |
}, function (e) { | |
done(false); | |
}) | |
}; | |
window.WAPI.getProfilePicFromId = function (id, done) { | |
window.Store.ProfilePicThumb.find(id).then(function (d) { | |
if (d.imgFull !== undefined) { | |
window.WAPI.downloadFileWithCredentials(d.imgFull, done); | |
} else { | |
done(false); | |
} | |
}, function (e) { | |
done(false); | |
}) | |
}; | |
window.WAPI.downloadFileWithCredentials = function (url, done) { | |
let xhr = new XMLHttpRequest(); | |
xhr.onload = function () { | |
if (xhr.readyState == 4) { | |
if (xhr.status == 200) { | |
let reader = new FileReader(); | |
reader.readAsDataURL(xhr.response); | |
reader.onload = function (e) { | |
done(reader.result.substr(reader.result.indexOf(',') + 1)) | |
}; | |
} else { | |
console.error(xhr.statusText); | |
} | |
} else { | |
console.log(err); | |
done(false); | |
} | |
}; | |
xhr.open("GET", url, true); | |
xhr.withCredentials = true; | |
xhr.responseType = 'blob'; | |
xhr.send(null); | |
}; | |
window.WAPI.downloadFile = function (url, done) { | |
let xhr = new XMLHttpRequest(); | |
xhr.onload = function () { | |
if (xhr.readyState == 4) { | |
if (xhr.status == 200) { | |
let reader = new FileReader(); | |
reader.readAsDataURL(xhr.response); | |
reader.onload = function (e) { | |
done(reader.result.substr(reader.result.indexOf(',') + 1)) | |
}; | |
} else { | |
console.error(xhr.statusText); | |
} | |
} else { | |
console.log(err); | |
done(false); | |
} | |
}; | |
xhr.open("GET", url, true); | |
xhr.responseType = 'blob'; | |
xhr.send(null); | |
}; | |
window.WAPI.getBatteryLevel = function (done) { | |
if (window.Store.Conn.plugged) { | |
if (done !== undefined) { | |
done(100); | |
} | |
return 100; | |
} | |
output = window.Store.Conn.battery; | |
if (done !== undefined) { | |
done(output); | |
} | |
return output; | |
}; | |
window.WAPI.deleteConversation = function (chatId, done) { | |
let userId = new window.Store.UserConstructor(chatId, {intentionallyUsePrivateConstructor: true}); | |
let conversation = WAPI.getChat(userId); | |
if (!conversation) { | |
if (done !== undefined) { | |
done(false); | |
} | |
return false; | |
} | |
window.Store.sendDelete(conversation, false).then(() => { | |
if (done !== undefined) { | |
done(true); | |
} | |
}).catch(() => { | |
if (done !== undefined) { | |
done(false); | |
} | |
}); | |
return true; | |
}; | |
window.WAPI.deleteMessage = function (chatId, messageArray, revoke=false, done) { | |
let userId = new window.Store.UserConstructor(chatId, {intentionallyUsePrivateConstructor: true}); | |
let conversation = WAPI.getChat(userId); | |
if(!conversation) { | |
if(done !== undefined) { | |
done(false); | |
} | |
return false; | |
} | |
if (!Array.isArray(messageArray)) { | |
messageArray = [messageArray]; | |
} | |
let messagesToDelete = messageArray.map(msgId => window.Store.Msg.get(msgId)); | |
if (revoke) { | |
conversation.sendRevokeMsgs(messagesToDelete, conversation); | |
} else { | |
conversation.sendDeleteMsgs(messagesToDelete, conversation); | |
} | |
if (done !== undefined) { | |
done(true); | |
} | |
return true; | |
}; | |
window.WAPI.checkNumberStatus = function (id, done) { | |
window.Store.WapQuery.queryExist(id).then((result) => { | |
if( done !== undefined) { | |
if (result.jid === undefined) throw 404; | |
done(window.WAPI._serializeNumberStatusObj(result)); | |
} | |
}).catch((e) => { | |
if (done !== undefined) { | |
done(window.WAPI._serializeNumberStatusObj({ | |
status: e, | |
jid : id | |
})); | |
} | |
}); | |
return true; | |
}; | |
/** | |
* New messages observable functions. | |
*/ | |
window.WAPI._newMessagesQueue = []; | |
window.WAPI._newMessagesBuffer = (sessionStorage.getItem('saved_msgs') != null) ? JSON.parse(sessionStorage.getItem('saved_msgs')) : []; | |
window.WAPI._newMessagesDebouncer = null; | |
window.WAPI._newMessagesCallbacks = []; | |
window.Store.Msg.off('add'); | |
sessionStorage.removeItem('saved_msgs'); | |
window.WAPI._newMessagesListener = window.Store.Msg.on('add', (newMessage) => { | |
if (newMessage && newMessage.isNewMsg && !newMessage.isSentByMe) { | |
let message = window.WAPI.processMessageObj(newMessage, false, false); | |
if (message) { | |
window.WAPI._newMessagesQueue.push(message); | |
window.WAPI._newMessagesBuffer.push(message); | |
} | |
// Starts debouncer time to don't call a callback for each message if more than one message arrives | |
// in the same second | |
if (!window.WAPI._newMessagesDebouncer && window.WAPI._newMessagesQueue.length > 0) { | |
window.WAPI._newMessagesDebouncer = setTimeout(() => { | |
let queuedMessages = window.WAPI._newMessagesQueue; | |
window.WAPI._newMessagesDebouncer = null; | |
window.WAPI._newMessagesQueue = []; | |
let removeCallbacks = []; | |
window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) { | |
if (callbackObj.callback !== undefined) { | |
callbackObj.callback(queuedMessages); | |
} | |
if (callbackObj.rmAfterUse === true) { | |
removeCallbacks.push(callbackObj); | |
} | |
}); | |
// Remove removable callbacks. | |
removeCallbacks.forEach(function (rmCallbackObj) { | |
let callbackIndex = window.WAPI._newMessagesCallbacks.indexOf(rmCallbackObj); | |
window.WAPI._newMessagesCallbacks.splice(callbackIndex, 1); | |
}); | |
}, 1000); | |
} | |
} | |
}); | |
window.WAPI._unloadInform = (event) => { | |
// Save in the buffer the ungot unreaded messages | |
window.WAPI._newMessagesBuffer.forEach((message) => { | |
Object.keys(message).forEach(key => message[key] === undefined ? delete message[key] : ''); | |
}); | |
sessionStorage.setItem("saved_msgs", JSON.stringify(window.WAPI._newMessagesBuffer)); | |
// Inform callbacks that the page will be reloaded. | |
window.WAPI._newMessagesCallbacks.forEach(function (callbackObj) { | |
if (callbackObj.callback !== undefined) { | |
callbackObj.callback({ status: -1, message: 'page will be reloaded, wait and register callback again.' }); | |
} | |
}); | |
}; | |
window.addEventListener("unload", window.WAPI._unloadInform, false); | |
window.addEventListener("beforeunload", window.WAPI._unloadInform, false); | |
window.addEventListener("pageunload", window.WAPI._unloadInform, false); | |
/** | |
* Registers a callback to be called when a new message arrives the WAPI. | |
* @param rmCallbackAfterUse - Boolean - Specify if the callback need to be executed only once | |
* @param done - function - Callback function to be called when a new message arrives. | |
* @returns {boolean} | |
*/ | |
window.WAPI.waitNewMessages = function (rmCallbackAfterUse = true, done) { | |
window.WAPI._newMessagesCallbacks.push({ callback: done, rmAfterUse: rmCallbackAfterUse }); | |
return true; | |
}; | |
/** | |
* Reads buffered new messages. | |
* @param done - function - Callback function to be called contained the buffered messages. | |
* @returns {Array} | |
*/ | |
window.WAPI.getBufferedNewMessages = function (done) { | |
let bufferedMessages = window.WAPI._newMessagesBuffer; | |
window.WAPI._newMessagesBuffer = []; | |
if (done !== undefined) { | |
done(bufferedMessages); | |
} | |
return bufferedMessages; | |
}; | |
/** End new messages observable functions **/ | |
window.WAPI.sendImage = function (imgBase64, chatid, filename, caption, done) { | |
//var idUser = new window.Store.UserConstructor(chatid); | |
var idUser = new window.Store.UserConstructor(chatid, { intentionallyUsePrivateConstructor: true }); | |
// create new chat | |
return Store.Chat.find(idUser).then((chat) => { | |
var mediaBlob = window.WAPI.base64ImageToFile(imgBase64, filename); | |
var mc = new Store.MediaCollection(chat); | |
mc.processAttachments([{file: mediaBlob}, 1], chat, 1).then(() => { | |
var media = mc.models[0]; | |
media.sendToChat(chat, { caption: caption }); | |
if (done !== undefined) done(true); | |
}); | |
}); | |
} | |
window.WAPI.base64ImageToFile = function (b64Data, filename) { | |
var arr = b64Data.split(','); | |
var mime = arr[0].match(/:(.*?);/)[1]; | |
var bstr = atob(arr[1]); | |
var n = bstr.length; | |
var u8arr = new Uint8Array(n); | |
while (n--) { | |
u8arr[n] = bstr.charCodeAt(n); | |
} | |
return new File([u8arr], filename, {type: mime}); | |
}; | |
/** | |
* Send contact card to a specific chat using the chat ids | |
* | |
* @param {string} to '[email protected]' | |
* @param {string|array} contact '[email protected]' | ['[email protected]', '[email protected], ... '[email protected]'] | |
*/ | |
window.WAPI.sendContact = function (to, contact) { | |
if (!Array.isArray(contact)) { | |
contact = [contact]; | |
} | |
contact = contact.map((c) => { | |
return WAPI.getChat(c).__x_contact; | |
}); | |
if (contact.length > 1) { | |
window.WAPI.getChat(to).sendContactList(contact); | |
} else if (contact.length === 1) { | |
window.WAPI.getChat(to).sendContact(contact[0]); | |
} | |
}; | |
/** | |
* Create an chat ID based in a cloned one | |
* | |
* @param {string} chatId '[email protected]' | |
*/ | |
window.WAPI.getNewMessageId = function (chatId) { | |
var newMsgId = Store.Msg.models[0].__x_id.clone(); | |
newMsgId.fromMe = true; | |
newMsgId.id = WAPI.getNewId().toUpperCase(); | |
newMsgId.remote = chatId; | |
newMsgId._serialized = `${newMsgId.fromMe}_${newMsgId.remote}_${newMsgId.id}` | |
return newMsgId; | |
}; | |
/** | |
* Send Customized VCard without the necessity of contact be a Whatsapp Contact | |
* | |
* @param {string} chatId '[email protected]' | |
* @param {object|array} vcard { displayName: 'Contact Name', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name;;;\nEND:VCARD' } | [{ displayName: 'Contact Name 1', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name 1;;;\nEND:VCARD' }, { displayName: 'Contact Name 2', vcard: 'BEGIN:VCARD\nVERSION:3.0\nN:;Contact Name 2;;;\nEND:VCARD' }] | |
*/ | |
window.WAPI.sendVCard = function (chatId, vcard) { | |
var chat = Store.Chat.get(chatId); | |
var tempMsg = Object.create(Store.Msg.models.filter(msg => msg.__x_isSentByMe)[0]); | |
var newId = window.WAPI.getNewMessageId(chatId); | |
var extend = { | |
ack : 0, | |
id : newId, | |
local : !0, | |
self : "out", | |
t : parseInt(new Date().getTime() / 1000), | |
to : chatId, | |
isNewMsg: !0, | |
}; | |
if (Array.isArray(vcard)) { | |
Object.assign(extend, { | |
type : "multi_vcard", | |
vcardList: vcard | |
}); | |
delete extend.body; | |
} else { | |
Object.assign(extend, { | |
type : "vcard", | |
subtype: vcard.displayName, | |
body : vcard.vcard | |
}); | |
delete extend.vcardList; | |
} | |
Object.assign(tempMsg, extend); | |
chat.addAndSendMsg(tempMsg); | |
}; | |
/** | |
* Block contact | |
* @param {string} id '[email protected]' | |
* @param {*} done - function - Callback function to be called when a new message arrives. | |
*/ | |
window.WAPI.contactBlock = function (id, done) { | |
const contact = window.Store.Contact.get(id); | |
if (contact !== undefined) { | |
contact.setBlock(!0); | |
done(true); | |
return true; | |
} | |
done(false); | |
return false; | |
} | |
/** | |
* unBlock contact | |
* @param {string} id '[email protected]' | |
* @param {*} done - function - Callback function to be called when a new message arrives. | |
*/ | |
window.WAPI.contactUnblock = function (id, done) { | |
const contact = window.Store.Contact.get(id); | |
if (contact !== undefined) { | |
contact.setBlock(!1); | |
done(true); | |
return true; | |
} | |
done(false); | |
return false; | |
} | |
/** | |
* Remove participant of Group | |
* @param {*} idGroup '[email protected]' | |
* @param {*} idParticipant '[email protected]' | |
* @param {*} done - function - Callback function to be called when a new message arrives. | |
*/ | |
window.WAPI.removeParticipantGroup = function (idGroup, idParticipant, done) { | |
window.Store.WapQuery.removeParticipants(idGroup, [idParticipant]).then(() => { | |
const metaDataGroup = window.Store.GroupMetadata.get(id) | |
checkParticipant = metaDataGroup.participants._index[idParticipant]; | |
if (checkParticipant === undefined) { | |
done(true); return true; | |
} | |
}) | |
} | |
/** | |
* Promote Participant to Admin in Group | |
* @param {*} idGroup '[email protected]' | |
* @param {*} idParticipant '[email protected]' | |
* @param {*} done - function - Callback function to be called when a new message arrives. | |
*/ | |
window.WAPI.promoteParticipantAdminGroup = function (idGroup, idParticipant, done) { | |
window.Store.WapQuery.promoteParticipants(idGroup, [idParticipant]).then(() => { | |
const metaDataGroup = window.Store.GroupMetadata.get(id) | |
checkParticipant = metaDataGroup.participants._index[idParticipant]; | |
if (checkParticipant !== undefined && checkParticipant.isAdmin) { | |
done(true); return true; | |
} | |
done(false); return false; | |
}) | |
} | |
/** | |
* Demote Admin of Group | |
* @param {*} idGroup '[email protected]' | |
* @param {*} idParticipant '[email protected]' | |
* @param {*} done - function - Callback function to be called when a new message arrives. | |
*/ | |
window.WAPI.demoteParticipantAdminGroup = function (idGroup, idParticipant, done) { | |
window.Store.WapQuery.demoteParticipants(idGroup, [idParticipant]).then(() => { | |
const metaDataGroup = window.Store.GroupMetadata.get(id) | |
if (metaDataGroup === undefined) { | |
done(false); return false; | |
} | |
checkParticipant = metaDataGroup.participants._index[idParticipant]; | |
if (checkParticipant !== undefined && checkParticipant.isAdmin) { | |
done(false); return false; | |
} | |
done(true); return true; | |
}) | |
} | |
function checkStatus() { | |
return (localStorage.WASecretBundle !== undefined || localStorage.WARoutingInfo !== undefined) ? 0 : -1; | |
} | |
function runCheckMessages() { | |
if (localStorage.WASecretBundle === undefined && localStorage.WARoutingInfo === undefined) return -1; | |
return document.querySelectorAll('[aria-label*="unread message"]').length; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment