您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
try to take over the world!
当前为
// ==UserScript== // @name Togetter User Ban // @namespace https://gf.qytechs.cn/ja/scripts/387330-togetter-user-ban // @version 0.1 // @description try to take over the world! // @author You // @match https://togetter.com/* // @grant none // ==/UserScript== /** * ユーザーを表すデータ型 * @typedef {Object} User * @property {string} userId * @property {string} icon */ /** * @param {string} userId * @param {string} icon * @returns {User} */ const User = (userId, icon) => { return { userId: userId, icon: icon }; }; /** * user1がuser2と同じユーザーを示すか判別します。 * @param {User} user1 * @param {User} user2 */ const isSameUser = (user1, user2) => { return (user1.userId === user2.userId); }; /** * 与えられた時間だけスレッドを停止します。 * @param {number} ms ミリ秒 */ const sleep = ms => { return new Promise(resolve => { setTimeout(resolve, ms); }); }; /** * 文字列からHTMLElementを作り返します。 * @param {string} h htmlを表現する文字列 * @returns {HTMLElement} */ const html = h => { const div = document.createElement("div"); div.insertAdjacentHTML("afterbegin", h); return div.firstChild; } /** * userListがuserを持っているか判別します。 * @param {User[]} userList * @param {User} user */ const userContains = (userList, user) => userList.filter(i => isSameUser(i, user)).length > 0; /** * objListをJSON CSVに変換して返します。 * @param {{}[]} objList */ const objListToJson = objList => objList.map(o => JSON.stringify(o)).join(","); //------------------------------------------------------------------------------------------------- const parser = {}; /** * strをstringの配列にして返します。 * @param {string} str '["hoge", "fuga"]'のような配列を意味する文字列 */ parser.list = str => str.replace(/\[|\]/g, "").split(/,(?={)/); /** * strをオブジェクトの形式にして返します。 * @param {string} str '{"name":"tanaka","sex":"male"}'のようなオブジェクトを意味する文字列 */ parser.json = str => { const obj = {}; str.replace(/"/g, "") // '{"userId":"hoge","icon":"fuga.jpg"}' -> '{userId:hoge,icon:fuga.jpg}' .replace(/{|}/g, "") // -> "userId:hoge,icon:fuga.jpg" .split(",") // -> ["userId:hoge", "icon:fuga.jpg"] .some(i => { const kvPair = i.split(/(?<!https):/); if (kvPair.length !== 2) return true; obj[kvPair[0]] = kvPair[1]; }); return obj; }; //------------------------------------------------------------------------------------------------- const ele = {}; /** * @param {User} user */ ele.li = user => { const li = html( `<li class="clearfix" style="display: flex;"> <a href="/id/${user.userId}" title="@${user.userId}" style="flex: auto;"> <p class="">@${user.userId}</p> <img class="icon_24 lazy lazy-hidden loaded" src="${user.icon}"> </a> </li>`); const button = html(`<button style="width: 1.5em; height: 1.5em; font-size: 14px; margin: auto; margin-right: 5px; margin-left: 5px;">×</button>`); button.onclick = () => { dao.delete(user); li.parentElement.removeChild(li); }; li.appendChild(button); return li; }; /** * @param {User[]} users */ ele.div = users => { const lis = users.map(u => ele.li(u)); const div = html( `<div class="side_box side_line_box list_recommend expandable scrollable"> <h3 class="title">バンリスト</h3> <div class="main_box closed"> <ul> </ul> </div> </div>`); lis.forEach(l => div.querySelector("div.main_box ul").appendChild(l)); return div; }; /** * ユーザーのバンやバン解除を行うボタンを返します。 * @param {User} user */ ele.button = user => { const isBanned = userContains(dao.find(), user); const text = isBanned ? "バンしている" : "バンする"; const clazz = isBanned ? "btn active" : "btn"; const button = html(`<a class="${clazz}" data-title="バンする" data-active-title="バンしている" data-active-hover-title="バンを解除する">${text}</a>`); const clickEvent = () => { const isActive = button.classList.contains("active"); if (isActive) { dao.delete(user); button.setAttribute("class", "btn"); button.innerText = button.getAttribute("data-title"); console.log(`${user.userId}のバンを解除しました。`); } else { dao.add(user); button.setAttribute("class", "btn active"); button.innerText = button.getAttribute("data-active-title"); console.log(`${user.userId}をバンしました。`); }; }; const hoverEvent = () => { const isActive = button.classList.contains("active"); if (!isActive) return false; button.innerText = button.getAttribute("data-active-hover-title"); }; const outEvent = () => { const isActive = button.classList.contains("active"); if (!isActive) return false; button.innerText = button.getAttribute("data-active-title"); }; button.onclick = clickEvent; button.onmouseover = hoverEvent; button.onmouseout = outEvent; return button; }; //------------------------------------------------------------------------------------------------- const dao = {}; /** * ローカルストレージに保存されたユーザーの配列を返します。 * @returns {User[]} */ dao.find = () => { const raw = localStorage.bannedUser; if (raw === undefined || raw === "[]") return []; return raw.split(/,(?={)/).map(i => JSON.parse(i)); }; /** * ローカルストレージにuserを保存します。 * @param {User} user */ dao.add = user => { const bannedUsers = dao.find(); if (!userContains(bannedUsers, user)) bannedUsers.push(user); const jsonList = objListToJson(bannedUsers); dao.save(jsonList); }; /** * ローカルストレージからuserを消去します。 * @param {User} user */ dao.delete = user => { const bannedUsers = dao.find(); const newUserList = bannedUsers.filter(i => !isSameUser(i, user)); const jsonList = objListToJson(newUserList); dao.save(jsonList); }; /** * ローカルストレージのbannedUserキーに文字列を保存します。 * @param {string} str */ dao.save = str => localStorage.setItem("bannedUser", str); //HTMLの取得と操作--------------------------------------------------------------------------------- /** * 条件に一致した要素を見えなくします。 * @param {string} eleSel 消したい要素のセレクター * @param {string} checkEleSel eleSelを祖先に持ち、かつattrを有する要素のセレクター * @param {string} attr 要素を消す基準の属性。"text"を与えた場合はinnerTextを探す。 * @param {string[]} bannedList バンリスト */ const hideElement = (eleSel, checkEleSel, attr, bannedList) => { document.querySelectorAll(eleSel).forEach(ele => { const innerEle = ele.querySelector(checkEleSel); if (innerEle === null) return false; const property = (attr === "text") ? innerEle.innerText : innerEle.getAttribute(attr); if (bannedList.includes(property) && ele.style.display !== "none") { ele.style.display = "none"; console.log(`hideElement: 要素を消しました。(${property})`); }; }); }; /** * togetterサイトのフォローボタンを格納したボックスを返します。 * バンボタンを設置するのに使います。 */ const followBox = () => document.querySelector("#follow_box"); /** * togetterサイトのプロフィールボックスを返します。 */ const profileBox = () => document.querySelector("div.profile_box").parentElement; /** * バンボタンを設置します。 */ const addBanButton = () => { const profile = profileBox(); const userId = profile.querySelector("a.status_name").innerText.replace("@", ""); const icon = profile.querySelector("img").getAttribute("src"); const user = User(userId, icon); followBox().appendChild(ele.button(user)); }; /** * バンリストを設置します。 */ const addBannedList = () => { const bannedUsers = dao.find(); const div = ele.div(bannedUsers); document.querySelector("#right_wrap_middle .right_wrap").appendChild(div); }; /** * 特定のユーザーが作ったまとめを非表示にします。 * @param {User[]} bannedList 非表示にしたいユーザーのリスト */ const hideMatome = bannedList => { hideElement("li.clearfix", "img.icon_24", "data-lazy-src", bannedList.map(u => u.icon)); }; /** * 特定のユーザーのコメントを非表示にします。 * @param {User[]} bannedList 非表示にしたいユーザーのリスト */ const hideComment = bannedList => { hideElement("#comment_box .list_box", ".status_name", "text", bannedList.map(u => u.userId).map(i => "@" + i)); }; /** * 最近見たまとめなどのリストに表示されている、特定のユーザーの作ったまとめを非表示にします。 * @param {User[]} bannedList 非表示にしたいユーザーのリスト */ const hideThumbList = bannedList => { hideElement("ul.simple_list.thumb_list li", "img.icon_20", "data-lazy-src", bannedList.map(u => u.icon)); }; /** * @param {Function} callback コールバック * @param {number} ms */ const thread = async (callback, ms = 300) => { while (true) { callback(); await sleep(ms); }; }; (async () => { 'use strict'; addBannedList(); const bannedList = dao.find(); thread(() => hideThumbList(bannedList)); if (location.href.startsWith("https://togetter.com/id/")) { addBanButton(); return false; }; if (location.href.startsWith("https://togetter.com/li/")) { addBanButton(); thread(() => hideComment(bannedList)); return false; }; thread(() => hideMatome(bannedList)); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址