Skip to content

Instantly share code, notes, and snippets.

@sueszli
Created August 8, 2023 23:48
Show Gist options
  • Save sueszli/04056ff03813084f0dcfa14b81fa1dd5 to your computer and use it in GitHub Desktop.
Save sueszli/04056ff03813084f0dcfa14b81fa1dd5 to your computer and use it in GitHub Desktop.
track all chats from your whatsapp browser client
// ==UserScript==
// @name WhatsApp Chats
// @namespace sueszli
// @match *://*web.whatsapp.com/*
// @grant none
// @version 1.0
// @author sueszli
// @description Simple utility functions to read chat elements from active and archived chats.
// ==/UserScript==
// How to use:
// 1. install userscript manager: https://violentmonkey.github.io/
// 2. click on `RAW` button - Then the script will be installed in your browser automatically.
// ======================================== CONFIG ========================================
let selectedChats = ['Test 0', 'Test 1', 'Test 2']
// ========================================================================================
function applicationReady() {
const logOutButtonPath = "//body/div[@id='app']/div[1]/div[1]/div[5]/div[1]"
return new Promise((resolve, reject) => {
const el = getNodes(logOutButtonPath)
if (!el) {
resolve(el)
}
new MutationObserver((mutationRecords, observer) => {
const e = getNodes(logOutButtonPath)
if (e.length === 0) {
resolve(getNodes(logOutButtonPath))
observer.disconnect()
}
}).observe(document.documentElement, {
childList: true,
subtree: true,
})
})
}
function elementReady(xPath) {
return new Promise((resolve, reject) => {
const el = getNodes(xPath)
if (el) {
resolve(el)
}
new MutationObserver((mutationRecords, observer) => {
if (getNodes(xPath).length === 0) {
resolve(getNodes(xPath))
observer.disconnect()
}
}).observe(document.documentElement, {
childList: true,
subtree: true,
})
})
}
function getNodes(xpath) {
let nodes = []
let result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null)
let node = result.iterateNext()
while (node) {
nodes.push(node)
node = result.iterateNext()
}
return nodes
}
function getFirstNode(xPath) {
return getNodes(xPath)[0]
}
function getLastChats() {
let sidePanel = getFirstNode("//body/div[@id='app']/div[1]/div[1]/div[3]/div[1]/div[2]/div[2]/div[1]/div[1]")
let chatElems = sidePanel.children
for (let i = 0; i < chatElems.length; i++) {
let contactName = chatElems[i].querySelector("[role='gridcell'] span").innerText
if (selectedChats.includes(contactName)) {
console.log('%c[selected] Active Chat: ' + contactName, 'background: #222; color: #bada55')
} else {
console.log('Active Chat: ' + contactName)
}
}
}
function getArchivedChats() {
getFirstNode("//body/div[@id='app']/div[1]/div[1]/div[3]/div[1]/div[2]/button[1]").click()
const sidePanelPath = "//body/div[@id='app']/div[1]/div[1]/div[2]/div[1]/span[1]/div[1]/span[1]/div[1]/div[1]/div[1]/div[1]/div[1]"
elementReady(sidePanelPath).then(() => {
let sidePanel = getFirstNode(sidePanelPath)
let chatElems = sidePanel.children
for (let i = 0; i < chatElems.length; i++) {
let contactName = chatElems[i].querySelector("[role='gridcell'] span").innerText
if (selectedChats.includes(contactName)) {
console.log('%c[selected] Archived Chat: ' + contactName, 'background: #222; color: #bada55')
} else {
console.log('Archived Chat: ' + contactName)
}
}
getFirstNode('//header/div[1]/div[1]/button[1]').click()
})
}
;(function () {
'use strict'
window.addEventListener('load', () => {
applicationReady().then(() => {
console.clear()
console.log('Starting script...\n')
getLastChats()
getArchivedChats()
})
})
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment