Github屏蔽用户

屏蔽Github搜索页面某些丝麻用户的内容,如cirosantilli发的与代码无关的Shit Repo,我囸你写吗狗罕见

// ==UserScript==
// @name        Github屏蔽用户
// @namespace   Violentmonkey Scripts
// @match       https://github.com/*
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       unsafeWindow
// @grant       GM_registerMenuCommand
// @version     1.0
// @author      Gwen0x4c3
// @license     MIT
// @description 屏蔽Github搜索页面某些丝麻用户的内容,如cirosantilli发的与代码无关的Shit Repo,我囸你写吗狗罕见
// ==/UserScript==
(function() {
  'use strict';
  
  const log = {
    info(message, obj) {
      if (typeof(message) == 'string') {
        console.log("%c[INFO] " + message, "color:blue;font-weight:bold;", obj);
      } else {
        console.log("%c[INFO] ", "color:blue;font-weight:bold;", arguments);
      }
    },
    error(message, obj) {
      if (typeof(message) == 'string') {
        console.log("%c[ERROR] " + message, "color:red;font-weight:bold;", obj);
      } else {
        console.log("%c[ERROR] ", "color:red;font-weight:bold;", arguments);
      }
    }
  }
  
  const REGEX_SEARCH_REPO = /\/search\?.*?type=repositories.*?/;
  const REGEX_SEARCH_USER = /\/search\?.*?type=users.*?/;
  const REGEX_EXCLUDE_USER = /-user:([a-zA-Z0-9_]+)/g;
  
  const store = {
    blockedUsers: GM_getValue("blocked_users", ['cirosantilli', 'wumaoland']),
    dialog: null
  }
  
  GM_registerMenuCommand("⚙查看屏蔽用户", () => {
    store.dialog.show();
  });
  
  function createElement(tag, clazz, attrs) {
    const elem = document.createElement(tag);
    elem.className = clazz;
    if (attrs) {
      for (let key in attrs) {
        elem[key] = attrs[key];
      }
    }
    return elem;
  }
  
  function blockElem(target) {
    const div = createElement('div', target.className, {
      innerText: `🚫Blocked this shit content by user: ${target.getAttribute('gb_user')}`
    })
    target.replaceWith(div);
  }
  
  function blockRepoSearch() {
    const resultList = document.querySelector('div[data-testid="results-list"]');
    // log.info("获取results list", { resultList });
    if (!resultList || resultList.gb_blocked) {
      setTimeout(blockRepoSearch, 100);
    } else {
      resultList.gb_blocked = true;
      const repos = resultList.children;
      for (let i = 0; i < repos.length; i++) {
        const repo = repos[i];
        const span = repo.querySelector('.search-match');
        log.info({repo, span});
        const user = span.innerText.split('/')[0];
        repo.setAttribute('gb_user', user);
        for (let blockedUser of store.blockedUsers) {
          if (blockedUser == user) {
            log.info("BLOCKED " + span.innerText);
            blockElem(repo);
            break;
          }
        }
        const exampleButton = repo.querySelector('button');
        const blockButton = createElement('button', exampleButton.className, {
          innerText: '🚫Block',
          onclick: e => {
            if (confirm("Are you sure to BLOCK this MF:" + user)) {
              store.blockedUsers.push(user);
              GM_setValue('blocked_users', store.blockedUsers);
              for (let j = 0; j < repos.length; j++) {
                if (repos[j].getAttribute('gb_user') == user) {
                  blockElem(repos[j]);
                }
              }
            }
          }
        });
        blockButton.setAttribute('data-size', 'small');
        const buttonWrapper = createElement('div', exampleButton.parentElement.className);
        buttonWrapper.appendChild(blockButton);
        exampleButton.parentElement.parentElement.prepend(buttonWrapper);
      }
    }
  }
  
  function blockUserSearch() {
    const resultList = document.querySelector('div[data-testid="results-list"]');
    // log.info("获取results list", { resultList });
    if (!resultList || resultList.gb_blocked) {
      setTimeout(blockRepoSearch, 100);
    } else {
      resultList.gb_blocked = true;
      const users = resultList.children;
      for (let i = 0; i < users.length; i++) {
        const userElem = users[i];
        const a = user.querySelector('a:last-of-type');
        const user = a.innerText;
        userElem.setAttribute('gb_user', user);
        for (let blockedUser of store.blockedUsers) {
          if (blockedUser == user) {
            log.info("BLOCKED " + span.innerText);
            blockElem(userElem);
            break;
          }
        }
        const exampleButton = user.querySelector('button');
        const blockButton = createElement('button', exampleButton.className, {
          innerText: '🚫Block',
          onclick: e => {
            if (confirm("Are you sure to BLOCK this MF:" + user)) {
              store.blockedUsers.push(user);
              GM_setValue('blocked_users', store.blockedUsers);
              for (let j = 0; j < users.length; j++) {
                if (users[j].getAttribute('gb_user') == user) {
                  // users[j].remove();
                  // j--;
                  blockElem(users[j]);
                }
              }
            }
          }
        });
        blockButton.setAttribute('data-size', 'small');
        const buttonWrapper = createElement('div', exampleButton.parentElement.className);
        buttonWrapper.appendChild(blockButton);
        exampleButton.parentElement.parentElement.prepend(buttonWrapper);
      }
    }
  }
  
  function initDialog() {
    if (document.getElementById('gb_block_dialog')) {
      return;
    }
    const dialog = createElement('dialog', '', {
      id: 'gb_block_dialog',
      style: 'width:50%;position:fixed;left:0;top:50px;'
    });
    store.dialog = dialog;
    const closeBtn = createElement('span', '', {
      innerText: '×',
      style: 'position:absolute;right:5px;top:2px;font-size:18px;cursor:pointer',
      onclick: e => {
        dialog.close();
      }
    })
    const tips = createElement('p', '', {
      innerText: '多个用户使用英文逗号","分隔',
      style: 'text-align: center'
    })
    const textArea = createElement('textarea', '', {
      style: 'width:100%;min-height:200px;font-size:18px;resize:none;',
      value: store.blockedUsers.join(', '),
      onblur: e => {
        const arr = textArea.value.split(',');
        for (let i = 0; i < arr.length; i++) {
          arr[i] = arr[i].trim();
          if (arr[i].length == 0) {
            arr.splice(i, 1);
            i--;
          }
        }
        store.blockedUsers = [...arr];
        GM_setValue('blocked_users', store.blockedUsers);
        textArea.value = arr.join(', ');
      }
    })
    dialog.appendChild(closeBtn);
    dialog.appendChild(tips);
    dialog.appendChild(textArea);
    document.body.append(dialog);
  }
  
  function handleUrlChange(url) {
    initDialog();
    // const _url = new URL(url);
    // if (_url.pathname == '/search') {
    //   let q = _url.searchParams.get('q');
    //   if (!q) {
    //     q = '';
    //   }
    //   let users = [];
    //   let match = null;
    //   while ((match = REGEX_EXCLUDE_USER.exec(q)) !== null) {
    //     users.push(match[1]);
    //   }
    // }
    if (REGEX_SEARCH_REPO.test(lastUrl)) {
      blockRepoSearch();
    } else if (REGEX_SEARCH_USER.test(lastUrl)) {
      blockUserSearch();
    }
  }
  
  let lastUrl = '';
  handleUrlChange(location.href);
  const urlTimer = setInterval(() => {
    if (lastUrl != location.href) {
      log.info("url changed to " + location.href);
      lastUrl = location.href;
      handleUrlChange(lastUrl);
    }
  }, 300);
})();