Created
February 3, 2025 21:23
-
-
Save lwcorp/b4d3ae4f3f7d79d8a6164f49cdcd3075 to your computer and use it in GitHub Desktop.
LinkedIn Group sorting (both in search mode and when listing a user's groups) - including auto scrolling and optionally show just joined groups
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
(async function() { | |
// Helper: Converts text like "12K members" or "27,289 members" to a number. | |
// This version considers text until the first space or line break. | |
function parseMemberCount(text) { | |
text = text.replace(/,/g, '').trim(); | |
const token = text.split(/[\s\n]/)[0]; | |
const match = token.match(/([\d.]+)([KkMm]?)/); | |
if (!match) return 0; | |
let num = parseFloat(match[1]); | |
const suffix = match[2].toLowerCase(); | |
if (suffix === 'k') { | |
num *= 1000; | |
} else if (suffix === 'm') { | |
num *= 1000000; | |
} | |
return num; | |
} | |
let container, countSelector, filterFn, items; | |
let isCase1 = false; | |
// Detect Case 1: items are direct <li> children of [role="list"] | |
const case1Item = document.querySelector('[role="list"]>li'); | |
if (case1Item) { | |
container = case1Item.parentElement; | |
items = Array.from(container.querySelectorAll(':scope > li')); | |
// The member count is inside: div:nth-of-type(2) > div > div:nth-of-type(2) | |
countSelector = 'div:nth-of-type(2) > div > div:nth-of-type(2)'; | |
// Filter: keep only items that do NOT contain a <button>. | |
filterFn = li => !li.querySelector('button'); | |
isCase1 = true; | |
} else { | |
// Otherwise, attempt Case 2. | |
const case2Item = document.querySelector('.active li.pvs-list__paged-list-item'); | |
if (!case2Item) { | |
alert("No groups found"); | |
return; | |
} | |
container = case2Item.parentElement; | |
items = Array.from(container.querySelectorAll('li.pvs-list__paged-list-item')); | |
// The member count is in an element with class ".pvs-entity__caption-wrapper" | |
countSelector = '.pvs-entity__caption-wrapper'; | |
// Filter: keep only items that have a <button> whose first trimmed line equals "Joined" | |
filterFn = li => { | |
const btn = li.querySelector('button'); | |
if (!btn) return false; | |
const firstLine = btn.textContent.trim().split("\n")[0].trim(); | |
return firstLine === "Joined"; | |
}; | |
} | |
// Function to detect if the page shows paging (e.g., pagination numbers). | |
function hasPaging() { | |
return !!document.querySelector('.artdeco-pagination__pages--number'); | |
} | |
// Auto-scroll: scrolls down until no new content is loaded. | |
async function autoScrollToBottom() { | |
return new Promise(resolve => { | |
let lastHeight = document.documentElement.scrollHeight; | |
function scrollDown() { | |
window.scrollTo(0, document.documentElement.scrollHeight); | |
setTimeout(() => { | |
const newHeight = document.documentElement.scrollHeight; | |
if (newHeight > lastHeight) { | |
lastHeight = newHeight; | |
scrollDown(); | |
} else { | |
resolve(); | |
} | |
}, 1000); | |
} | |
scrollDown(); | |
}); | |
} | |
// If there's no paging element, auto-scroll down to trigger lazy loading, | |
// then scroll back up and wait a moment for the scroll up to complete. | |
if (!hasPaging()) { | |
await autoScrollToBottom(); | |
window.scrollTo(0, 0); | |
await new Promise(resolve => setTimeout(resolve, 500)); // wait for the scroll-up to settle | |
// Re-select items in case additional groups were loaded. | |
if (isCase1) { | |
items = Array.from(container.querySelectorAll(':scope > li')); | |
} else { | |
items = Array.from(container.querySelectorAll('li.pvs-list__paged-list-item')); | |
} | |
} | |
// Sort the items by member count in descending order. | |
items.sort((a, b) => { | |
const aCountEl = a.querySelector(countSelector); | |
const bCountEl = b.querySelector(countSelector); | |
const aCount = aCountEl ? parseMemberCount(aCountEl.textContent) : 0; | |
const bCount = bCountEl ? parseMemberCount(bCountEl.textContent) : 0; | |
return bCount - aCount; | |
}); | |
// Ask the user whether to show all groups or only the filtered ones. | |
const showAll = confirm("Show ALL groups? (OK = all; Cancel = filtered)"); | |
const finalItems = showAll ? items : items.filter(filterFn); | |
// Clear the container and re-append the sorted (and optionally filtered) items. | |
container.innerHTML = ""; | |
finalItems.forEach(item => container.appendChild(item)); | |
})(); |
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
javascript:(async function(){function p(t){t=t.replace(/,/g,"").trim();const a=t.split(/[\s\n]/)[0],m=a.match(/([\d.]+)([KkMm]?)/);if(!m)return 0;let n=parseFloat(m[1]),s=m[2].toLowerCase();return s==="k"?n*=1e3:s==="m"&&(n*=1e6),n}let c,cs,f,its,isC1=false;const c1=document.querySelector('[role="list"]>li');if(c1){c=c1.parentElement;its=Array.from(c.querySelectorAll(":scope > li"));cs="div:nth-of-type(2) > div > div:nth-of-type(2)";f=li=>!li.querySelector("button");isC1=true}else{const c2=document.querySelector(".active li.pvs-list__paged-list-item");if(!c2){alert("No groups found");return;}c=c2.parentElement;its=Array.from(c.querySelectorAll("li.pvs-list__paged-list-item"));cs=".pvs-entity__caption-wrapper";f=li=>{const b=li.querySelector("button");if(!b)return!1;const fl=b.textContent.trim().split("\n")[0].trim();return fl==="Joined"}}function hasPaging(){return!!document.querySelector(".artdeco-pagination__pages--number")}async function sD(){return new Promise(r=>{let l=document.documentElement.scrollHeight;function d(){window.scrollTo(0,document.documentElement.scrollHeight);setTimeout(()=>{const nh=document.documentElement.scrollHeight;nh>l?(l=nh,d()):r()},1e3)}d()})}if(!hasPaging()){await sD();window.scrollTo(0,0);await new Promise(r=>setTimeout(r,500));its=isC1?Array.from(c.querySelectorAll(":scope > li")):Array.from(c.querySelectorAll("li.pvs-list__paged-list-item"))}its.sort((a,b)=>{const ae=a.querySelector(cs),be=b.querySelector(cs),ac=ae?p(ae.textContent):0,bc=be?p(be.textContent):0;return bc-ac});const sa=confirm("Show ALL groups? (OK = all; Cancel = filtered)"),fi=sa?its:its.filter(f);c.innerHTML="";fi.forEach(i=>c.appendChild(i))})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment