// ==UserScript== // @name Twitter One-Click Block Button // @namespace https://gist.github.com/toxicwind // @version 1.2 // @description Adds a block button to every tweet in order to quickly block people. // @author toxicwind // @license MIT // @match https://twitter.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=twitter.com // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js // @grant none // @run-at document-end // @downloadURL https://update.greasyfork.icu/scripts/447841/Twitter%20One-Click%20Block%20Button.user.js // @updateURL https://update.greasyfork.icu/scripts/447841/Twitter%20One-Click%20Block%20Button.meta.js // ==/UserScript== const css = ` a.block-button { display: flex; align-items: center; justify-content: center; } a.block-button svg { width: 1em; height: 1em; fill: currentcolor; } a.block-button { transition: color 0.5s; } a.block-button:hover { color: red; } @keyframes wide { 0% { width: 0% } 100% { width: 60%; } }`; const style = document.createElement("style"); style.textContent = css; document.head.appendChild(style); (async () => { let fetchToken = async () => { let mainUrl = null; for (let script of document.body.querySelectorAll("script[src]")) if (/\/main\.[^\/]*\.js$/.test(script.src)) mainUrl = script.src; if (!mainUrl) return null; let response = await fetch(mainUrl); let mainSource = await response.text(); let result = /\"AAAAAAA[^"]+\"/.exec(mainSource); if (!result || result.length != 1) return null; return JSON.parse(result[0]); }; let authToken = await fetchToken(); let getCookie = (cname) => { const name = `${cname}=`; const decodedCookie = decodeURIComponent(document.cookie); const ca = decodedCookie.split(";"); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) == " ") { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; }; let blockUser = async (userName) => { return await fetch("https://api.twitter.com/1.1/blocks/create.json", { credentials: "include", referrer: "https://api.twitter.com/1.1/blocks/create.json", body: `screen_name=${userName}`, method: "POST", mode: "cors", headers: { "x-twitter-auth-type": "OAuth2Session", "x-twitter-client-language": "en", "x-twitter-active-user": "yes", "x-csrf-token": getCookie("ct0"), authorization: `Bearer ${authToken}`, "Content-Type": "application/x-www-form-urlencoded", }, }); }; let buttonClick = async (e) => { let userName = e.currentTarget.dataset.blockUser; let blockResult = await blockUser(userName); if (blockResult.status === 200) { $("article") .find("a[data-block-user=" + userName + "]") .parents("article[data-testid=tweet]") .slideUp(200); //alert("User blocked successfully."); } else { alert( "The block operation failed, see the network tab for detailes of the failure." ); } }; const icon = ` ยท `; let observer; const interval = setInterval(init, 500); function init() { const el = document.querySelectorAll( 'div[data-testid="primaryColumn"] section article' ); if (el && el.length > 0) { clearInterval(interval); debug("articles found"); //add links to already exisiting articles observer = new MutationObserver(newTweets); observer.observe(document.body, { childList: true, attributes: false, subtree: true, characterData: false, }); el.forEach((article) => { createLink(article); }); } } function newTweets(mutationList, observer) { mutationList.forEach((mut) => { if (mut.addedNodes.length > 0) { mut.addedNodes.forEach((node) => { if (node.innerHTML && node.innerHTML.indexOf("
-1) { createLink(node.querySelector("article")); } }); } }); } function createLink(t) { if (!t.querySelector("a[block-button]")) { const profileName = t .querySelector("div[data-testid=User-Names]") .querySelector("a") .pathname.substr(1); const time = t.querySelector('a[href*="/status/"] time[datetime]'); if (!time) return; const statuslink = time.parentNode; const block_link = document.createElement("a"); block_link.setAttribute("class", "block-button"); block_link.setAttribute("data-block-user", profileName); block_link.innerHTML = icon; statuslink.insertAdjacentElement("afterend", block_link); block_link.title = "Block User: " + profileName; block_link.onclick = buttonClick; } } })();