Created
April 12, 2023 19:32
-
-
Save Heartade/c90b919c60e975a2c8a7c93c9655147c to your computer and use it in GitHub Desktop.
Dirty userscript that gets twitter follows along with user uuid and description
This file contains 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 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