非公開 NGワードで自動アク禁(open2ch対応)

  • /*
    * @title NGワードで自動アク禁(open2ch対応)
    * @description open2ch.net用 連投対策版
    * @include http://*
    * @license MIT License
    * @private
    */
    
    
    let ngwords = prompt('NGワード(,区切り)', '').split(',').map(w => w.trim()).filter(w => w);
    let ngnames = prompt('NGネーム(,区切り)', '').split(',').map(w => w.trim()).filter(w => w);
    let nggyou = Number(prompt('行数制限(1以下入れるとバグる)\nInfinityで無効','Infinity'));
    
    let lastdetectednum = 0;
    let checkedPosts = new Set();
    
    // 四字熟語リスト
    const idioms = [
      "因果応報","悪霊退散","業報必至","破邪顕正","正邪明断",
      "天罰覿面","自業自得","除災招福","報復無道","悪即滅善"
    ];
    
    // MutationObserverで新規投稿の追加を監視
    const observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        mutation.addedNodes.forEach(function(node) {
          if(node.nodeType === 1 && node.tagName === 'DL') {
            checkPost($(node));
          }
        });
      });
    });
    
    const threadElement = document.querySelector('.thread');
    if(threadElement) {
      observer.observe(threadElement, {
        childList: true,
        subtree: false
      });
    }
    
    function checkPost($post) {
      let postnum = $post.attr('val');
      
      if(checkedPosts.has(postnum)) {
        return;
      }
      checkedPosts.add(postnum);
      
      let $dd = $post.find('>dd');
      let $dt = $post.find('>dt');
      let postText = $dd.text();
      let nameText = $dt.find('.name').text();
      
      // NGワードチェック
      for(let word of ngwords) {
        if(word && postText.includes(word)) {
          sendAkuCommand(postnum);
          return;
        }
      }
      
      // NGネームチェック
      for(let name of ngnames) {
        if(name && nameText.includes(name)) {
          sendAkuCommand(postnum);
          return;
        }
      }
      
      // 行数制限チェック
      let lineCount = postText.split('\n').length - 1;
      if(lineCount > nggyou) {
        sendAkuCommand(postnum);
        return;
      }
    }
    
    function sendAkuCommand(postnum) {
      if(lastdetectednum === postnum) return;
      
      lastdetectednum = postnum;
      const randomIdiom = idioms[Math.floor(Math.random() * idioms.length)];
      
      // 四字熟語を含めたメッセージを作成
      const message = '!aku' + postnum + '\n' + randomIdiom;
      
      $.ajax({
        type: 'POST',
        url: '/test/bbs.cgi',
        data: {
          MESSAGE: message,
          bbs: bbs,
          key: bbskey,
          submit: '書'
        },
        success: function() {
          console.log('%c!aku' + postnum + ' → ' + randomIdiom, 'color:gold;font-size:20px;font-weight:bold');
        },
        error: function() {
          console.log('%cアク禁コマンド送信失敗', 'color:red;font-size:20px;');
        }
      });
    }
    
    console.log(`%cNGワード「${ngwords.join(', ')}」\nNGネーム「${ngnames.join(', ')}」\n行数制限「${nggyou}行」\n監視方法:MutationObserver(新規投稿のみ)`, "font-size:16px;");
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。