您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a button that eliminates evil replys to tweet details.
当前为
// ==UserScript== // @name KoebutaSlayer // @namespace https://github.com/albno273/KoebutaSlayer // @description Adds a button that eliminates evil replys to tweet details. // @description:ja ツイート詳細に声豚のリプライを抹殺するボタンを追加します。 // @include https://twitter.com/* // @version 2.0.4 // @require https://openuserjs.org/src/libs/sizzle/GM_config.js // @grant GM_getValue // @grant GM_setValue // @grant GM_log // @grant GM_registerMenuCommand // @license MIT License // ==/UserScript== // 使用スクリプト: GM config // https://openuserjs.org/src/libs/sizzle/GM_config.js // 参考: Extract images for Twitter // https://gf.qytechs.cn/ja/scripts/15271-extract-images-for-twitter 'use strict'; // 除外リスト(初期設定) const defaultWhitelistArray = [ '0309akari', '0812asumikana', '38kMarie', 'AyakaOhashi', 'Emiryun', 'Erietty_55', 'ErikoMatsui', 'HiRoMi_ig', 'Lynn_0601_', 'Miho_Aaaa', 'OnoSaki1126', 'RiccaTachibana', 'TomoyoKurosawa', 'Uesakasumire', 'Yaskiyo_manager', 'akekodao', 'coloruri', 'eerie_eery', 'fuchigami_mai', 'han_meg_han', 'ibuking_1114', 'kanekosanndesu', 'kurapimk', 'maaya_taso', 'makomorino', 'marika_0222', 'mikakokomatsu', 'mikami_shiori', 'nanjolno', 'nojomiy', 'numakura_manami', 'osorasan703', 'ousakichiyo', 'reimatsuzaki', 'shimoda_asami', 'shiori_izawa', 'suzaki_aya', 'takamori_723', 'tanezakiatsumi', 'yuichupunch', 'yukari_tamura', 'yuuka_aisaka', 'yuumin_uchiyama' ]; // 初期設定 GM_config.init( { 'id': 'KoebutaSlayerConfig', 'title': 'KoebutaSlayer 設定', 'fields': { 'slayBehavior': { 'label': '抹殺時の挙動', 'type': 'radio', 'options': ['非表示にする', 'ニンジャスレイヤー風'], 'default': '非表示にする' }, 'whitelist': { 'label': 'ホワイトリスト(ID を改行で区切って入力してください)', 'type': 'textarea', 'default': `${defaultWhitelistArray.join('\n')}` } }, 'events': { 'save': () => { // 単語構成文字と改行以外の文字があったら注意 if(/[^0-9_a-zA-Z\n]/g.test(GM_config.fields['whitelist'].toValue())) alert('Caution!\nホワイトリストに半角英数字とアンダーバー、' + '改行以外の文字が入っていませんか?'); alert('設定を保存しました。'); }, 'reset': () => { alert('設定を初期化しました。'); } } } ); GM_registerMenuCommand("抹殺設定", () => { GM_config.open(); }); (() => { const processedList = new WeakMap(), processedTweetList = new WeakMap(); let slayCount = 0, // ツイート抹殺数 isSlayed = false; // 抹殺ボタンを作る const createSlayer = (tweetList) => { const slayer = document.createElement('div'); slayer.setAttribute('class', 'ProfileTweet-action js-toggleState ProfileTweet-action--Slay'); slayer.innerHTML = '<button class="ProfileTweet-actionButton js-actionButton js-actionSlay" type="button">' + '<div class="IconContainer js-tooltip" title="抹殺">' + '<span class="Icon Icon--close"></span>' + '<span class="u-hiddenVisually">抹殺</span>' + '</div>' + '<div class="IconTextContainer">' + '<span class="ProfileTweet-actionCount ">' + '<span class="ProfileTweet-actionCountForPresentation Slay-counter" aria-hidden="true"></span>' + '</span>' + '</div>' + '</button>'; const icon = slayer.getElementsByClassName('Icon')[0], counter = slayer.getElementsByClassName('Slay-counter')[0]; slayer.addEventListener('mouseenter', () => { icon.style.color = 'darkred'; counter.style.color = 'darkred'; }); slayer.addEventListener('mouseleave', () => { if(!isSlayed) { icon.style.color = ''; counter.style.color = ''; } }); slayer.addEventListener('click', () => { slayTweet(tweetList); if(slayCount != 0) { isSlayed = true; // 抹殺したツイート数を更新 setTimeout(() => { counter.textContent = slayCount; }, 500); } }); return slayer; }; // 抹殺ボタンを追加 const addSlayer = () => { const tweetList = document.getElementsByClassName('ProfileTweet-actionList'); for (let i = 0, len = tweetList.length; i < len; i++) { const tweet = tweetList[i]; if(!processedList.has(tweet)) { // 画面遷移前のボタンが残った時に削除 const oldSlayer = tweet.getElementsByClassName('ProfileTweet-action--Slay')[0]; if(oldSlayer) oldSlayer.remove(); // ホワイトリストに入ってるアカウントのツイートの詳細欄にのみボタンを登録 // TODO: parentNode 連打やめたい const tweetGGparent = tweet.parentNode.parentNode.parentNode, wl = GM_config.get('whitelist').split('\n'), id = /@(\w+)/g.exec(tweetGGparent.innerText)[1]; if(tweetGGparent.classList.contains('permalink-tweet-container')) { if(wl.indexOf(id) >= 0) { processedList.set(tweet, 1); tweet.appendChild(createSlayer(tweetList)); } } } } }; // ツイートを抹殺 const slayTweet = (tweetList) => { const behavior = GM_config.get('slayBehavior'), wl = GM_config.get('whitelist').split('\n'); for (let i = 0, len = tweetList.length; i < len; i++) { // 画面遷移前のツイートも含まれるのでリプライのみ抽出 // TODO: parentsNode 連打やめたい const tweets = tweetList[i].parentNode.parentNode.parentNode.parentNode .getElementsByClassName('permalink-descendant-tweet'); if(tweets.length == 1) { const tweet = tweets[0], from = tweet.getAttribute('data-screen-name'), to = tweet.getAttribute('data-mentions'); if(!processedTweetList.has(tweet)) { // チェインはされてるけど @id が明記されていない場合 if(wl.indexOf(from) == -1 && to == null) slay(behavior, tweet); else { const toArr = to.split(' '); toArr.forEach((value, index, array) => { if (wl.indexOf(from) == -1 && wl.indexOf(value) >= 0) slay(behavior, tweet); }); } } } } }; const slay = (behavior, tweet) => { if(behavior == '非表示にする') tweet.style.display = 'none'; else if(behavior == 'ニンジャスレイヤー風') { tweet.getElementsByClassName('tweet-text')[0].textContent = 'アバーッ!'; tweet.getElementsByClassName('fullname')[0].textContent = 'Koebuta Slayer'; tweet.getElementsByClassName('username')[0].innerHTML = '<s>@</s><b>koebutaslayer</b>'; tweet.getElementsByClassName('js-action-profile-avatar')[0] .setAttribute('src', 'https://pbs.twimg.com/profile_images/716042850903830528/PLNG3AVA.jpg'); const media = tweet.getElementsByClassName('AdaptiveMediaOuterContainer')[0]; if(media) media.remove(); } processedTweetList.set(tweet, 1); slayCount++; } // DOMの更新が入るたびにボタンを追加 (() => { let DOMObserverTimer = false; const DOMObserverConfig = { attributes: true, childList: true, subtree: true }; const DOMObserver = new MutationObserver(() => { if (DOMObserverTimer !== 'false') { clearTimeout(DOMObserverTimer); } DOMObserverTimer = setTimeout(() => { DOMObserver.disconnect(); addSlayer(); DOMObserver.observe(document.body, DOMObserverConfig); }, 100); }); DOMObserver.observe(document.body, DOMObserverConfig); })(); // 初回起動 addSlayer(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址