// ==UserScript== // @name X/Twitter 1 Click report spam and block // @description Report spam and block profiles with 1 click // @version 1.4 // @grant none // @match https://twitter.com/* // @match https://x.com/* // @author incognico // @icon https://www.google.com/s2/favicons?sz=64&domain=x.com // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2 // @license GPL v3 // @author incognico // @namespace https://greasyfork.org/users/931787 // // @downloadURL https://update.greasyfork.icu/scripts/495206/XTwitter%201%20Click%20report%20spam%20and%20block.user.js // @updateURL https://update.greasyfork.icu/scripts/495206/XTwitter%201%20Click%20report%20spam%20and%20block.meta.js // ==/UserScript== const accountMenuIconSelector = '[data-testid="primaryColumn"] svg:has([d="M3 12c0-1.1.9-2 2-2s2 .9 2 2-.9 2-2 2-2-.9-2-2zm9 2c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm7 0c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"])'; const ourIconId = 'oneclickreportbtn'; const reportIconSelector = '[data-testid="Dropdown"] svg:has([d="M3 2h18.61l-3.5 7 3.5 7H5v6H3V2zm2 12h13.38l-2.5-5 2.5-5H5v10z"])'; const spamItemSelector = '[data-viewportview="true"] [role="radiogroup"] label:nth-child(6)'; const nextButtonSelector = '[data-testid="ChoiceSelectionNextButton"]'; const modalButtonsSelector = '[data-viewportview="true"] button'; const wait = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); }; const doReport = async (event) => { if (!event.shiftKey) { alert('Press shift to confirm reporting this account as spam and blocking'); return; } // open account overflow menu document.querySelector(accountMenuIconSelector).parentElement.click(); await wait(100); // press report document.querySelector(reportIconSelector).parentElement.parentElement.click(); await wait(850); // select spam and press next document.querySelector(spamItemSelector).click(); document.querySelector(nextButtonSelector).click(); await wait(500); // second button is report document.querySelectorAll(modalButtonsSelector)[1].click(); }; const destroyIcon = () => { const icon = document.getElementById(ourIconId); if (icon) { icon.remove(); } }; const createIconIfNotExists = () => { const iconExists = document.getElementById(ourIconId); const accountMenuIcon = document.querySelector(accountMenuIconSelector); if (!iconExists && accountMenuIcon) { const icon = document.createElement('button'); icon.id = ourIconId; icon.innerHTML = ``; icon.title = '1-Click spam report & block'; icon.onclick = doReport; // assign style to the button const style = { color: 'black', textAlign: 'center', fontWeight: 'bold', alignSelf: 'baseline', borderRadius: '50%', borderColor: 'rgba(0, 0, 0, 0)', marginLeft: '5px', backgroundColor: 'rgb(239, 243, 244)', fontFamily: 'TwitterChirp, sans-serif', cursor: 'pointer', }; Object.assign(icon.style, style); // append icon to the profile icon list const header = accountMenuIcon.parentElement?.parentElement?.parentElement; if (header) { header.appendChild(icon); } } }; const disconnect = VM.observe(document.body, () => { // append our icon on profile pages const profilePage = document.querySelector('[data-testid="UserName"]'); if (profilePage) { createIconIfNotExists(); } else { destroyIcon(); } });