Skip to content

Instantly share code, notes, and snippets.

@Heartade
Created April 12, 2023 19:32
Show Gist options
  • Save Heartade/c90b919c60e975a2c8a7c93c9655147c to your computer and use it in GitHub Desktop.
Save Heartade/c90b919c60e975a2c8a7c93c9655147c to your computer and use it in GitHub Desktop.
Dirty userscript that gets twitter follows along with user uuid and description
// ==UserScript==
// @name TwitterGetFollows
// @namespace TwitterGetFollows
// @version 1
// @description Get Twitter Follow
// @match https://twitter.com/*
// @grant none
// ==/UserScript==
(function () {
"use strict";
/**
* @param {HTMLButtonElement} button
*/
function setButtonStyles(button) {
button.style.backgroundColor = "white";
button.style.border = "none";
button.style.display = "flex";
button.style.justifyContent = "center";
button.style.alignItems = "center";
button.style.borderRadius = "5px";
button.style.height = "28px";
}
const createShowHideButton = () => {
const showHideButton = document.createElement("button", {
id: "twitter-get-follows-show",
});
showHideButton.style.position = "fixed";
showHideButton.style.zIndex = "99999";
showHideButton.style.top = "8px";
showHideButton.style.right = "8px";
showHideButton.style.width = "28px";
showHideButton.innerHTML = "-";
setButtonStyles(showHideButton);
document.body.appendChild(showHideButton);
return showHideButton;
};
const showHideButton = createShowHideButton();
const createToolbar = () => {
const toolbar = document.createElement("div", {
id: "twitter-get-follows",
});
toolbar.style.position = "fixed";
toolbar.style.display = "flex";
toolbar.style.top = "8px";
toolbar.style.right = "40px";
toolbar.style.zIndex = "99999";
document.body.appendChild(toolbar);
return toolbar;
};
const toolbar = createToolbar();
showHideButton.addEventListener("click", () => {
if (toolbar.style.display == "none") {
showHideButton.innerHTML = "-";
toolbar.style.display = "flex";
showHideButton.style.backgroundColor = "rgba(242, 160, 160, 1)";
} else {
showHideButton.innerHTML = "+";
toolbar.style.display = "none";
showHideButton.style.backgroundColor = "rgba(150, 180, 235, 1)";
}
});
showHideButton.style.backgroundColor = "rgba(242, 160, 160, 1)";
function getUserHandle() {
let user_handle = localStorage.getItem("user_handle");
if (user_handle === null) {
return undefined;
} else {
return user_handle;
}
}
function setUserHandle() {
/**
* @type {HTMLAnchorElement}
*/
const profileButton = document
.querySelector('nav[aria-label="Primary"]')
.querySelector('a[aria-label="Profile"]');
let handle_href = profileButton.href.split("/");
let user_handle = handle_href[handle_href.length - 1];
localStorage.setItem("user_handle", user_handle);
return user_handle;
}
function getUserDescription() {
let user_description = localStorage.getItem("user_description");
if (user_description === null) {
return undefined;
} else {
return user_description;
}
}
function setUserDescription() {
/**
* @type {HTMLDivElement}
*/
let user_description = document
.querySelector('div[data-testid="UserDescription"]')
.querySelector("span").innerText;
localStorage.setItem("user_description", user_description);
}
function getUserFollowingCount() {
let user_following_count = localStorage.getItem("user_following_count");
if (user_following_count === null) {
return undefined;
} else {
let user_following_count_integer = parseInt(user_following_count);
if (isNaN(user_following_count_integer)) return undefined;
else return user_following_count_integer;
}
}
function setUserFollowingCount() {
/**
* @type {HTMLAnchorElement}
*/
let user_following_count = document
.querySelector('a[href="/' + getUserHandle() + '/following"]')
.querySelector("span").innerText;
// filter only numbers
user_following_count = user_following_count.replace(/[^0-9]/g, "");
console.log("UserFollowingCount: ", user_following_count);
localStorage.setItem("user_following_count", user_following_count);
}
function getUserFollowersCount() {
let user_followers_count = localStorage.getItem("user_followers_count");
if (user_followers_count === null) {
return undefined;
} else {
let user_followers_count_integer = parseInt(user_followers_count);
if (isNaN(user_followers_count_integer)) return undefined;
else return user_followers_count_integer;
}
}
function setUserFollowersCount() {
/**
* @type {HTMLAnchorElement}
*/
let user_followers_count = document
.querySelector('a[href="/' + getUserHandle() + '/followers"]')
.querySelector("span").innerText;
// filter only numbers
user_followers_count = user_followers_count.replace(/[^0-9]/g, "");
console.log("UserFollowersCount: ", user_followers_count);
localStorage.setItem("user_followers_count", user_followers_count);
}
function getUserRestId() {
let user_rest_id = localStorage.getItem("user_rest_id");
if (user_rest_id === null) {
return undefined;
} else return user_rest_id;
}
/**
* @returns {Array<{"id": string, "handle": string, "description": string}> | undefined}
*/
function getUserFollowing() {
let user_following = localStorage.getItem("user_following");
if (user_following === null) {
return undefined;
} else return JSON.parse(user_following);
}
/**
* @returns {Array<{"id": string, "handle": string, "description": string}> | undefined}
*/
function getUserFollowers() {
let user_followers = localStorage.getItem("user_followers");
if (user_followers === null) {
return undefined;
} else return JSON.parse(user_followers);
}
function shouldAdvanceToFollowing() {
return (
getUserHandle() !== undefined &&
getUserFollowersCount() !== undefined &&
getUserFollowingCount() !== undefined &&
getUserRestId() !== undefined &&
getUserDescription() !== undefined
);
}
function tryAdvanceToFollowing() {
if (shouldAdvanceToFollowing()) {
window.location.href = `https://twitter.com/${getUserHandle()}/following`;
} else {
console.log("Waiting for data...");
}
}
function shouldAdvanceToFollowers() {
return (
getUserFollowing() !== undefined &&
getUserFollowing().length >= getUserFollowingCount()
);
}
function tryAdvanceToFollowers() {
if (shouldAdvanceToFollowers()) {
window.location.href = `https://twitter.com/${getUserHandle()}/followers`;
} else {
console.log("Waiting for data...");
}
}
function shouldComplete() {
if (getUserFollowers() !== undefined) {
console.log(getUserFollowers().length);
console.log(getUserFollowersCount());
}
return (
getUserFollowers() !== undefined &&
getUserFollowers().length >= getUserFollowersCount()
);
}
function tryComplete() {
if (shouldComplete()) {
console.log(getUserHandle());
console.log(getUserRestId());
console.log(getUserDescription());
console.log(getUserFollowers());
console.log(getUserFollowing());
// window.alert("Done!");
}
}
if (window.location.href === "https://twitter.com/home") {
const initButton = document.createElement("button", {
id: "twitter-get-follows-get-handle",
});
setButtonStyles(initButton);
initButton.style.backgroundColor = "rgba(150, 242, 120, 1)";
toolbar.appendChild(initButton);
initButton.innerHTML = "Start Getting Follows";
initButton.addEventListener("click", () => {
localStorage.removeItem("user_handle");
localStorage.removeItem("user_description");
localStorage.removeItem("user_rest_id");
localStorage.removeItem("user_following_count");
localStorage.removeItem("user_followers_count");
localStorage.removeItem("user_following");
localStorage.removeItem("user_followers");
setUserHandle();
window.location.href = `https://twitter.com/${getUserHandle()}`;
});
} else if (
getUserHandle() !== undefined &&
window.location.href === "https://twitter.com/" + getUserHandle()
) {
toolbar.innerText = "Getting user profile...";
// Intercept XHR requests
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
if (url.indexOf("https://twitter.com/i/api/graphql") === 0) {
// Save a reference to the original send function
var send = this.send;
var xhr = this;
// console.log(url);
// Override the send function to intercept the response
this.send = function () {
xhr.addEventListener("load", function () {
if (getUserFollowingCount() === undefined) setUserFollowingCount();
if (getUserFollowersCount() === undefined) setUserFollowersCount();
if (getUserDescription() === undefined) setUserDescription();
if (
getUserHandle() !== undefined &&
url.includes("ProfileSpotlightsQuery")
) {
// get the user's rest id from profile
let user_handle = getUserHandle();
if (user_handle === undefined) return;
let profileSpotlights = JSON.parse(xhr.responseText);
const res_handle =
profileSpotlights["data"]["user_result_by_screen_name"][
"result"
]["legacy"]["screen_name"];
const res_id =
profileSpotlights["data"]["user_result_by_screen_name"][
"result"
]["id"];
console.log("Handle: " + res_handle);
console.log("ID: " + res_id);
console.log("UserHandle: " + user_handle);
if (res_handle === user_handle) {
// Log the response details to the console
console.log("RestId: " + res_id);
localStorage.setItem("user_rest_id", res_id);
}
}
tryAdvanceToFollowing();
});
send.apply(xhr, arguments);
};
}
open.apply(this, arguments);
};
} else if (
shouldAdvanceToFollowing() &&
window.location.href ===
"https://twitter.com/" + getUserHandle() + "/following"
) {
toolbar.innerText = "Getting user following...";
// Intercept XHR requests
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
if (url.indexOf("https://twitter.com/i/api/graphql") === 0) {
// Save a reference to the original send function
var send = this.send;
var xhr = this;
// console.log(url);
// Override the send function to intercept the response
this.send = function () {
xhr.addEventListener("load", function () {
if (getUserHandle() !== undefined && url.includes("Following")) {
// get the user's rest id from profile
let user_following = getUserFollowing();
if (user_following === undefined) user_following = [];
let following = JSON.parse(xhr.responseText);
const instructions =
following["data"]["user"]["result"]["timeline"]["timeline"][
"instructions"
];
for (let i = 0; i < instructions.length; i++) {
if (instructions[i]["type"] === "TimelineAddEntries") {
const res_list = instructions[i]["entries"];
// console.log(res_list);
if (res_list) {
for (let following of res_list) {
if (
following["content"]["entryType"] !==
"TimelineTimelineItem"
)
continue;
let userResult =
following["content"]["itemContent"]["user_results"][
"result"
];
let userHandle = userResult["legacy"]["screen_name"];
let userId = userResult["id"];
let userDescription = userResult["legacy"]["description"];
user_following.push({
handle: userHandle,
id: userId,
description: userDescription,
});
}
}
}
}
localStorage.setItem(
"user_following",
JSON.stringify(user_following)
);
// delay 0.1s
setTimeout(() => {
window.scrollBy(0, document.body.scrollHeight);
}, 100);
}
tryAdvanceToFollowers();
});
send.apply(xhr, arguments);
};
}
open.apply(this, arguments);
};
} else if (
shouldAdvanceToFollowers() &&
window.location.href ===
"https://twitter.com/" + getUserHandle() + "/followers"
) {
toolbar.innerText = "Getting user followers...";
// Intercept XHR requests
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
if (url.indexOf("https://twitter.com/i/api/graphql") === 0) {
// Save a reference to the original send function
var send = this.send;
var xhr = this;
// console.log(url);
// Override the send function to intercept the response
this.send = function () {
xhr.addEventListener("load", function () {
if (getUserHandle() !== undefined && url.includes("Followers")) {
// get the user's rest id from profile
let user_followers = getUserFollowers();
if (user_followers === undefined) user_followers = [];
let following = JSON.parse(xhr.responseText);
const instructions =
following["data"]["user"]["result"]["timeline"]["timeline"][
"instructions"
];
for (let i = 0; i < instructions.length; i++) {
if (instructions[i]["type"] === "TimelineAddEntries") {
const res_list = instructions[i]["entries"];
// console.log(res_list);
if (res_list) {
for (let following of res_list) {
if (
following["content"]["entryType"] !==
"TimelineTimelineItem"
)
continue;
let userResult =
following["content"]["itemContent"]["user_results"][
"result"
];
let userHandle = userResult["legacy"]["screen_name"];
let userId = userResult["id"];
let userDescription = userResult["legacy"]["description"];
user_followers.push({
handle: userHandle,
id: userId,
description: userDescription,
});
}
}
}
}
localStorage.setItem(
"user_followers",
JSON.stringify(user_followers)
);
// delay 0.1s
setTimeout(() => {
window.scrollBy(0, document.body.scrollHeight);
}, 100);
}
tryComplete();
});
send.apply(xhr, arguments);
};
}
open.apply(this, arguments);
};
// localStorage.removeItem("user_handle");
// localStorage.removeItem("user_description");
// localStorage.removeItem("user_rest_id");
// localStorage.removeItem("user_following_count");
// localStorage.removeItem("user_followers_count");
// localStorage.removeItem("user_following");
// localStorage.removeItem("user_followers");
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment