認証マークが表示されている場合にアイコンの下に「ブロック」と「通報」ボタンを設置する
なお認証マークは非表示機能がなくなったので判定基準として有用。身内は認証マークが付いてない人が大半なので丁度良い。
ユーザ名にも本文にも日本語が使われていないとボタンが赤くなり、片方だとオレンジみたいな仕様にしている
つまり赤い奴はクソ怪しいぞという感じ。
// ==UserScript==
// @name インプレゾンビぶっ殺しボタン
// @namespace http://tampermonkey.net/
// @version 2024-08-08
// @description アイコン画像の下にブロックボタンとスパム通報ボタンを追加する
// @author https://amemilk.com/
// @match https://x.com/*
// ==/UserScript==
(function() {
'use strict';
const createButton = (text, color, clickHandler) => {
const button = document.createElement("button");
button.style.cssText = `
font-size: 12px;
height: 16pt;
background-color: ${color};
color: white;
padding: 0px;
margin-top: 5px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
`;
button.textContent = text;
button.onclick = clickHandler;
return button;
};
const getButtonColor = (text, name) => {
const hasJapaneseInText = /[\u3040-\u30FF\u4E00-\u9FFF\u3005\u3006\u3007\u0024\u0030]/.test(text);
const hasJapaneseInName = /[\u3040-\u30FF\u4E00-\u9FFF\u3005\u3006\u3007\u0024\u0030]/.test(name);
if (!hasJapaneseInName && hasJapaneseInText) {
return 'orange';
} else if (!hasJapaneseInText || !hasJapaneseInName) {
return 'red';
} else {
return 'gray';
}
};
const handleBlock = (menuButton) => {
menuButton.click();
const blockInterval = setInterval(() => {
const blockOption = document.querySelector("div[role='menuitem'][data-testid='block']");
if (blockOption) {
clearInterval(blockInterval);
blockOption.click();
const confirmInterval = setInterval(() => {
const confirmButton = document.querySelector("button[data-testid='confirmationSheetConfirm']");
if (confirmButton) {
clearInterval(confirmInterval);
confirmButton.click();
}
}, 100);
}
}, 100);
};
const handleReport = (menuButton) => {
menuButton.click();
const reportInterval = setInterval(() => {
const reportOption = document.querySelector("div[role='menuitem'][data-testid='report']");
if (reportOption) {
clearInterval(reportInterval);
reportOption.click();
const checkboxInterval = setInterval(() => {
const checkbox = document.querySelector("input[aria-posinset='6']");
if (checkbox) {
clearInterval(checkboxInterval);
checkbox.click();
const nextButton = document.querySelector("button[data-testid='ChoiceSelectionNextButton']");
if (nextButton) {
nextButton.click();
const finalInterval = setInterval(() => {
const finalButton = document.querySelector("button[data-testid='ocfSettingsListNextButton']");
if (finalButton) {
clearInterval(finalInterval);
finalButton.click();
}
}, 100);
}
}
}, 100);
}
}, 100);
};
setInterval(() => {
document.querySelectorAll("div[data-testid='Tweet-User-Avatar']").forEach(e => {
if (e.getAttribute('data-block-button-added')) {
return;// すでにボタンが追加されている場合、処理をスキップ
}
const tweetElement = e.closest('article');
const menuButton = e.parentElement.parentElement.querySelector("button[aria-haspopup='menu']");
if (!menuButton) {
return;
}
const tweetText = tweetElement.querySelector("div[data-testid='tweetText']")?.innerText || '';
const userName = tweetElement.querySelector("div[data-testid='User-Name'] span")?.innerText || '';
const buttonColor = getButtonColor(tweetText, userName);
const blockButton = createButton("=リJワ=リ.ワ", buttonColor, () => handleBlock(menuButton));
const reportButton = createButton("=リィ゙", buttonColor, () => handleReport(menuButton));
e.append(blockButton);
e.append(reportButton);
e.setAttribute('data-block-button-added', 'true');// ボタンが追加されたことを記録
});
}, 1000);
})();