Created
September 30, 2024 22:21
-
-
Save MarksCode/5c71f8aeb6ed295f4870a1b5b204223c to your computer and use it in GitHub Desktop.
Bulk Remove LinkedIn Connections
This file contains hidden or 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
// ==UserScript== | |
// @name LinkedIn Connection Remover | |
// @author Ron Marks | |
// @version 1.0 | |
// @description Bulk Remove LinkedIn Connections | |
// @match https://www.linkedin.com/mynetwork/invite-connect/connections/ | |
// @run-at document-end | |
// @grant unsafeWindow | |
// ==/UserScript== | |
const LIST_CLASS = "scaffold-finite-scroll__content"; | |
const CONNECTION_CLASS = "mn-connection-card"; | |
const checkedConnections = []; | |
let messageObserver = null; | |
function waitForListElToExist() { | |
return new Promise((resolve) => { | |
const observer = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
if (!mutation.addedNodes) return; | |
for (let i = 0; i < mutation.addedNodes.length; i++) { | |
const node = mutation.addedNodes[i]; | |
if (node.classList && node.classList.contains(LIST_CLASS)) { | |
observer.disconnect(); | |
resolve(node); | |
return; | |
} | |
} | |
}); | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true, | |
}); | |
}); | |
} | |
/** | |
* Observes new connection elements. | |
* @param {HTMLElement} connectionsListEl | |
* @param {(connectionEl: HTMLElement) => void} callback | |
*/ | |
function observeNewConnections(connectionsListEl, callback) { | |
if (messageObserver) { | |
messageObserver.disconnect(); | |
} | |
messageObserver = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
if (!mutation.addedNodes) return; | |
for (let i = 0; i < mutation.addedNodes.length; i++) { | |
const node = mutation.addedNodes[i]; | |
if (node.classList && node.classList.contains(CONNECTION_CLASS)) { | |
callback(node); | |
} | |
} | |
}); | |
}); | |
messageObserver.observe(connectionsListEl, { | |
childList: true, | |
subtree: true, | |
}); | |
// Initial log of existing connections | |
const initialConnections = | |
connectionsListEl.getElementsByClassName(CONNECTION_CLASS); | |
for (let i = 0; i < initialConnections.length; i++) { | |
callback(initialConnections[i]); | |
} | |
} | |
function addRadioBoxToConnection(connectionEl) { | |
const radioBox = document.createElement("input"); | |
radioBox.type = "checkbox"; | |
radioBox.style.position = "absolute"; | |
radioBox.style.top = "50%"; | |
radioBox.style.left = "6px"; | |
radioBox.style.transform = "translateY(-50%)"; | |
radioBox.style.opacity = 1; | |
radioBox.style.width = "20px"; | |
radioBox.style.height = "20px"; | |
radioBox.style.pointerEvents = "all"; | |
radioBox.style.margin = 0; | |
radioBox.addEventListener("change", (e) => { | |
if (e.target.checked) { | |
checkedConnections.push(connectionEl); | |
} else { | |
checkedConnections.splice(checkedConnections.indexOf(connectionEl), 1); | |
} | |
}); | |
connectionEl.prepend(radioBox); | |
} | |
function sleep(delay) { | |
return new Promise((resolve) => setTimeout(resolve, delay)); | |
} | |
async function removeConnection(connectionEl) { | |
const dropdown = connectionEl.querySelector(".artdeco-dropdown__trigger"); | |
if (dropdown) { | |
dropdown.click(); | |
} | |
await sleep(1000); | |
const removeButton = Array.from(connectionEl.querySelectorAll("button")).find( | |
(el) => el.innerText === "Remove connection" | |
); | |
if (removeButton) { | |
removeButton.click(); | |
} | |
await sleep(1500); | |
const confirmButton = document.body.querySelector( | |
"button[data-test-dialog-primary-btn]" | |
); | |
if (confirmButton) { | |
confirmButton.click(); | |
} | |
await sleep(500); | |
} | |
function removeConnections() { | |
const firstConnection = checkedConnections[0]; | |
console.log("REMOVING CONNECTIONS", checkedConnections); | |
if (!firstConnection) { | |
return; | |
} | |
removeConnection(firstConnection).then(() => { | |
checkedConnections.shift(); | |
if (checkedConnections.length) { | |
removeConnections(); | |
} | |
}); | |
} | |
function addRemoveButton() { | |
const button = document.createElement("button"); | |
button.textContent = "Remove Selected"; | |
button.style.position = "fixed"; | |
button.style.top = "50%"; | |
button.style.right = "20%"; | |
button.style.transform = "translateY(-50%)"; | |
button.style.zIndex = 9999; | |
button.style.padding = "10px"; | |
button.style.border = "1px solid black"; | |
button.style.backgroundColor = "#cb112d"; | |
button.style.color = "white"; | |
button.style.cursor = "pointer"; | |
button.style.borderRadius = "5px"; | |
button.style.boxShadow = "0 2px 4px 0 rgba(0,0,0,0.2)"; | |
button.addEventListener("click", () => { | |
removeConnections(); | |
}); | |
document.body.appendChild(button); | |
} | |
(async function () { | |
addRemoveButton(); | |
const listEl = await waitForListElToExist(); | |
observeNewConnections(listEl, addRadioBoxToConnection); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment