Xのトレンドがスパムだらけ

ブラウザ拡張版が公開されたため以下は古い内容です。
ブラウザ拡張版についてはこちら

注意点

導入前の注意
  • Xの仕様変更で簡単に動かなくなりがちな作りとなっています。動作がおかしいと思ったらスクリプトをOFFにしてください。
  • ポストを読み込んだ後で非表示とするツールです(通信自体をブロックしている訳ではないためインプレッション稼ぎは阻止出来ません)
  • X側の想定外の動作をさせるため場合に寄ってはAPI呼び出し回数が増えたり不審な動作として凍結などされてしまう可能性があります。
  • そもそもこの記事のような知らない人、知らないサイトから取得したスクリプトを実行するのはかなり危険です。凍結リスクなどの上記事項含め利用は全て自己責任でお願いします。
導入後の注意
  • ミュートワード(BLOCK_WORDS)に設定した単語が検索結果に多く含まれると予想される検索を行わないでください(非表示→続き読み込み…が繰り返されAPI上限まで止まらなくなります)

バージョン更新(修正など) – 1.2.0

  • 更新の際はオプション部分のバックアップを取った上で「スクリプト使用方法 – 手順3」を再実施してください(新規作成などは不要です。旧コードを削除し新コードを貼り付け直してください)
2023/10/17 – v1.2.0
  • トレンドワードを羅列するスパム向けのオプションを追加しました(ひらがな・カタカナ・漢字の後に半角スペースを多用するポストを非表示に出来るオプションが追加されました)
過去の更新
2023/10/16 – v1.1.0
  • スマホでの使用に対応しました
2023/10/15 – v1.0.2
  • 非表示にしないワード(EXCLUDE_WORD)を設定していても非表示になってしまう問題を修正しました
2023/10/15 – v1.0.1
  • スクリプトが停止してしまうケースを修正しました
  • 「デフォルトアイコンアカウントのポスト非表示」オプションの初期設定をOFFに変更しました(以外と巻き込むケースが多かったため。任意でONに戻せます)
  • オプションのバックアップ範囲がわかりやすいようコメントを追加しました
  • おまけ機能の「ポスト数表示」をクリックすると開発者コンソールに非表示にしたポスト本文を出力する機能を追加しました(スパムでないポストが巻き込まれていないか確認用)
  • ハッシュタグ数による非表示機能が動作していなかった問題を修正しました

スクリプト使用方法

Androidスマホで使用する場合

Androidスマホで使用する場合は以下手順を参照してください

手順1.Chrome拡張機能ScriptAutoRunnerのインストール

【ScriptAutoRunner】
https://chromewebstore.google.com/detail/scriptautorunner/gpgjofmpmjjopcogjgdldidobhmjmdbm
以上の拡張機能をインストールしてください。
ScriptAutoRunnerでなくても任意のスクリプトをサイトに挿入出来るツールであればOKです。

手順2.ScriptAutoRunnerの設定

手順1でインストールしたScriptAutoRunnerの設定画面を開き、以下画像の通り設定してください

手順3.スクリプトを設定

以下のコードをコピーしてスクリプトに設定してください(画像赤枠部に貼り付け)

↓コピーするコード

/* --- Ver.1.2.0 ---*/
/* --- オプション使用可能バージョン(前Ver.のオプションをコピペで使える範囲) Ver.1.2.0 ~ Ver.1.2.0 --- */

/* ▼▼▼▼▼ オプションバックアップコピー範囲ここから ▼▼▼▼▼ */
/* ----- 【基本設定】 ----- */
/* 【非表示(ミュート)にするワード】必ず""で囲むこと。最終行以外は末尾に「,」を付けること */
const BLOCK_WORDS = [
    "非表示にするワード_記載例1",
    "非表示にするワード_記載例2"
    ];
    
    /* 【非表示に「しない」ワード】非表示にするワードと同じ形式で入力。非表示ワードとこちらの両方が一致する場合非表示にしない(こちらが優先) */
    const EXCLUDE_WORD = [
    "非表示にしないワード_サンプル1",
    "非表示にしないワード_サンプル2"
    ];
    
    /* 1つのポストにハッシュタグが指定数以上ある場合、非表示にする(ハッシュタグスパム対応)(0を指定した場合本機能無効) */
    const TAG_BORDER = 5;
    
    /* アイコン未設定ユーザーのポストを非表示にする */
    const DEFAULT_ICON_BLOCK = false;
    
    /* ブロックしたポスト数を表示する(おまけ機能) */
    const BLOCK_COUNT_VIEW = true;

    /* ひらがな・カタカナ・漢字の間にあるスペースが指定数以上あるポストを非表示にします(0で無効)(スペースで区切ってトレンドを列挙するスパム用) */
    const SPACE_BORDER = 5;
    
    /*
    
    
    
    
    
    
    
    
    ※以下は基本的に変更不要。必要に応じて設定。
    
    
    
    
    
    
    
    
    
    */
    
    /* ひらがなとカタカナを区別するか(「区別しない」場合、例えば「プロフ」と「ぷろふ」が同じ文字と見做される) */
    const HIRA_KATA_COV = true; /* true:区別しない false:区別する */
    
    /* INTERVAL_TIME 処理の実行間隔。ミリ秒で指定。処理が重いと感じる場合は数字を大きくすると軽くなるかも */
    const INTERVAL_TIME = 300;
    
    /* 非表示を適用するURL、先頭一致 */
    const TARGET_URL = [
    "twitter.com/search",
    "twitter.com/hashtag"
    ];
    
    /* trueの場合、twitter.comとx.comを同一ドメインと見做します */
    const URL_XT_CONVERT = true;
    
    /* 一致を確認する際に正規表現を使用するか */
    const REG_EXP = false;
    
    /* デフォルトアイコン画像 */
    const DEFAULT_ICON_NAME = "default_profile_normal.png";
    
    /* ポスト本文のクラスリスト */
    const POST_CLASS = [
        ["css-901oao css-cens5h r-18jsvk2 r-37j5jr r-a023e6 r-16dba41 r-rjixqe r-bcqeeo r-bnwqim r-qvutc0", 9],
        ["css-901oao css-cens5h r-1nao33i r-37j5jr r-1b43r93 r-16dba41 r-hjklzo r-bcqeeo r-bnwqim r-qvutc0", 9]
    ];
    
    /* ▲▲▲▲▲ オプションバックアップコピー範囲ここまで ▲▲▲▲▲ */
    
    /* ---------- スクリプト ---------- */
    
    let postBlockViewNumber = 0;
    let hidden_posts = [];
    let postClass_Hierarchy;
    
    function TwitterSearchBlockMain(){
        MainLoopX();
    }
    
    function MainLoopX(){
        let postList;
        if(FilterActiveCheck()){
            if(BLOCK_COUNT_VIEW){
                if(document.getElementById("x9uVvQH") != null){
                    if(document.getElementById("x9uVvQH").style.display == "none"){
                        postBlockViewNumber = 0;
                        hidden_posts = [];
                        BlockCount();
                    }
                    document.getElementById("x9uVvQH").style.display = "block";
                }
            }
            if(postClass_Hierarchy == null || postClass_Hierarchy == void 0){
                postClass_Hierarchy = getPostClass();
            }
            if(postClass_Hierarchy == void 0){
                setTimeout(MainLoopX, INTERVAL_TIME);
                return;
            }
            postList = document.getElementsByClassName(postClass_Hierarchy[0]);
    
            for(let i=0;i<postList.length;i++){
                if(PostBlockCheck(postList[i])){
                    hidden_posts.push(postList[i].innerText);
                    PostBlock(getPostParent(postList[i]));
                }
            }
        } else {
            if(document.getElementById("x9uVvQH") != null){
                document.getElementById("x9uVvQH").style.display = "none";
            }
        }
        setTimeout(MainLoopX, INTERVAL_TIME);
    }
    
    function getPostClass(){
        let l;
        for(let i=0;i<POST_CLASS.length;i++){
            l = document.getElementsByClassName(POST_CLASS[i][0]);
            if(0 < l.length){
                return POST_CLASS[i];
            }
        }
    }
    
    function PostBlockCheck(post){
        let postl = post.innerText.split(/\n/);
        if(REG_EXP){
            for(let i=0;i<EXCLUDE_WORD.length;i++){
                for(let p=0;p<postl.length;p++){
                    if(HiraToKana(postl[p]).match(HiraToKana(EXCLUDE_WORD[i]))){ return false; }
                }
            }
            for(let i=0;i<BLOCK_WORDS.length;i++){
                for(let p=0;p<postl.length;p++){
                    if(HiraToKana(postl[p]).match(HiraToKana(BLOCK_WORDS[i]))){ return true; }
                }
            }
        } else {
            for(let i=0;i<EXCLUDE_WORD.length;i++){
                for(let p=0;p<postl.length;p++){
                    if(HiraToKana(postl[p]).includes(HiraToKana(EXCLUDE_WORD[i]))){ return false; }
                }
            }
            for(let i=0;i<BLOCK_WORDS.length;i++){
                for(let p=0;p<postl.length;p++){
                    if(HiraToKana(postl[p]).includes(HiraToKana(BLOCK_WORDS[i]))){ return true; }
                }
            }
        }
        if(0 < TAG_BORDER){
            if(TAG_BORDER <= TagCount(post)){
                return true;
            }
        }
        if(0 < SPACE_BORDER){
            if(SPACE_BORDER  <= SpaceCount(post)){
                return true;
            }
        }
        if(DEFAULT_ICON_BLOCK){
            if(DefaultIcon(post)){
                return true;
            }
        }
        return false;
    }
    
    function PostBlock(post){
        if(post.style.visibility != "hidden"){
            post.style.visibility = "hidden";
            post.style.height = "0px";
            postBlockViewNumber++;
            if(BLOCK_COUNT_VIEW){
                BlockCount();
            }
        }
    }
    
    function HiraToKana(str){
        if(HIRA_KATA_COV){
            return str.replace( /[\u3042-\u3093]/g, m => String.fromCharCode(m.charCodeAt(0) + 96));
        } else {
            return str;
        }
    };
    
    function TagCount(post){
        let cnt = 0;
        let a = post.getElementsByTagName("a");
        for(let i=0;i<a.length;i++){
            if(a[i].href.includes("?src=hashtag_click")){
                cnt++;
            }
        }
        return cnt;
    }

    function SpaceCount(post){
        let cnt = 0;
        let a = post.innerText.split(/\n/);
        let r;
        for(let i=0;i<a.length;i++){
            r = a[i].trim().match(/[ | ][ぁ-んァ-ヶー一-龯]/g);
            if(r != null){
                cnt += r.length;
            }
        }
        cnt = cnt == null ? 0 : cnt;
        return cnt;
    }
    
    function DefaultIcon(post){
        let a = getPostParent(post).getElementsByTagName("img");
        for(let i=0;i<a.length;i++){
            if(a[i].src.endsWith(DEFAULT_ICON_NAME)){
                return true;
            }
        }
    }
    
    function FilterActiveCheck(){
        let url = getLUrl().replace("https://", "");
        for(let i=0;i<TARGET_URL.length;i++){
            if(url.startsWith(TARGET_URL[i])){ return true; }
        }
        return false;
    }
    
    function BlockCount(){
        if(document.getElementById("x9uVvQH") == null){
            let addtag = document.createElement("div");
            addtag.id = "x9uVvQH";
            addtag.style.position = "fixed";
            addtag.style.top = "0px";
            addtag.style.left = "0px";
            document.body.appendChild(addtag);
            document.getElementById("x9uVvQH").innerHTML = "<div style='border:solid 1px #cdcdcd;background-color:#FFF;cursor:pointer;padding:0.3em;'id='x9uVvQH_ar'>非表示数<br><span id='x9uVvQH_num' style='text-align:center;margin-right:0.2em;'></span>posts</div>";
            document.getElementById("x9uVvQH_ar").addEventListener("click", ConsoleOutput, false);
        }
        document.getElementById("x9uVvQH_num").innerText = postBlockViewNumber;
    }
    
    function ConsoleOutput(){
        if(window.confirm("非表示にしたポストをコンソールに出力しますか?")){
            console.info("【非表示にしたポスト】");
            console.info("※以下のオプションが設定されています");
            if(0 < TAG_BORDER){
                console.info("・ハッシュタグが" + TAG_BORDER + "以上あるポストの非表示");
            }
            if(DEFAULT_ICON_BLOCK){
                console.info("・プロフィールアイコン未設定アカウントからのポスト非表示");
            }
            if(0 < SPACE_BORDER){
                console.info("・ひらカタ漢の後にスペースが" + SPACE_BORDER + "以上あるポストの非表示");
            }
            console.log("----------");
            for(let i=0;i<hidden_posts.length;i++){
                if(hidden_posts[i].trim() != ""){
                    console.log(hidden_posts[i]);
                }
            }
            alert("出力しました。開発者ツールのコンソールを確認してください。");
        }
    }
    
    function getPostParent(post){
        let r = post;
        for(let i=0;i<postClass_Hierarchy[1];i++){
            r = r.parentElement;
        }
        return r;
    }
    
    function getLUrl(){
        let url = location.href;
        if(URL_XT_CONVERT){
            url = url.replace('x.com', 'twitter.com');
        }
        return url;
    }
    
    TwitterSearchBlockMain();

4.有効化して完了

背景が黄色くなればOKです

5.設定

ワードの設定などはスクリプト内に記載してあるのでそちら参考にスパムによく出てくる単語とかを設定してください

コメント