Skip to content

Instantly share code, notes, and snippets.

@Kenya-West
Created March 10, 2024 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kenya-West/0e489eb750bbdd240d372032c8b7d595 to your computer and use it in GitHub Desktop.
Save Kenya-West/0e489eb750bbdd240d372032c8b7d595 to your computer and use it in GitHub Desktop.
Collect channel usernames in Telegram Web (A)
// Because there is no API method nor programmatic access to Telegram channel usernames,
// this script was created. It is a workaround to collect usernames from the chat folder.
// It collects names and usernames and saves them to an array.
// 1. Open https://web.telegram.org/a/;
// 2. Open the chat filder. Main one is not supported! And there should be no "Archived chats" chat;
// 3. Open the browser console;
// 4. Paste the script and run it;
// 5. Wait for the script to finish. It should take a few minutes.
// Current bugs:
// - The script does not always collect usernames when chat is a forum.
let namesList = [];
let namesListDelta = 1;
let scrollingCounter = 0;
const scrollingCounterLimit = 5;
async function scrollAndCollectNames() {
while(namesListDelta > 0 || scrollingCounter < scrollingCounterLimit) {
console.log('Starting a new iteration...');
let delta = namesList.length;
let elems = Array.from(document.querySelectorAll("#LeftColumn.Transition .chat-list.Transition_slide-active .ListItem"));
// elems = elems.slice(0,3); // for testing purposes
console.log(`Found ${elems.length} elements...`);
await sleep(200);
for await (const elem of elems) {
console.log(`Processing elem with name: ${elem.querySelector(".info .info-row .title")?.innerText}...`);
const name = elem.querySelector(".info .info-row .title")?.innerText;
// setting username here is valid, yet it is costly in terms of performance and time
// so better to do it after filtering names so the loop will not start over again
// also worth noting that the username is not always available
// despite teh fact name is not unique, it is still a good enough identifier
// const username = await getUsername(elem);
if (!namesList.find(item => item.name === name)) {
namesList.push({
name,
username: await getUsername(elem)
});
}
}
namesListDelta = namesList.length - delta;
scrollingCounter++;
console.log(`Scrolling iteration ${scrollingCounter} completed. Names list delta: ${namesListDelta}`);
// two scroll methods: prefer 1st one
elems[elems.length-1]?.scrollIntoView();
// const chatList = document.querySelector(".chat-list.custom-scroll.Transition_slide.Transition_slide-active");
// chatList.scrollTo(0,9999);
await new Promise(resolve => setTimeout(resolve, 500));
}
}
async function getUsername(elem) {
async function simulateMouseClick(element){
console.log('Simulating mouse click...');
const mouseClickEvents = ['mousedown', 'click', 'mouseup'];
mouseClickEvents.forEach(mouseEventType =>
element.dispatchEvent(
new MouseEvent(mouseEventType, {
view: window,
bubbles: true,
cancelable: true,
buttons: 1
})
)
);
}
async function getUserNameText() {
console.log('Getting username...');
const rightPane = document.querySelector("#RightColumn");
const username = rightPane?.querySelector(".ChatExtra .ListItem:nth-child(2) .multiline-item .title")?.innerText || '<no username>';
return username;
}
console.log('Getting username for an element...', elem);
await simulateMouseClick(elem.querySelector(".ListItem-button"));
await sleep(2000); // wait for the click event to be processed
await simulateMouseClick(document.querySelector("#MiddleColumn .MiddleHeader .Transition .chat-info-wrapper"));
await sleep(2000); // wait for the click event to be processed
return await getUserNameText();
}
await scrollAndCollectNames().then(() => {
console.log('Finished collecting names.');
console.dir(namesList);
}).catch((e) => {
console.log('Finished collecting names.');
console.dir(namesList);
});
/**
*
* @param {number} ms
* @returns Promise
*/
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment