少数派屏蔽用户

请自行编辑屏蔽列表 blockedUsers,内容为用户主页地址,比如 https://sspai.com/u/vistaing/updates 中的 vistaing

// ==UserScript==
// @name         少数派屏蔽用户
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  请自行编辑屏蔽列表 blockedUsers,内容为用户主页地址,比如 https://sspai.com/u/vistaing/updates 中的 vistaing
// @author       duckmouse
// @match        https://sspai.com/
// @match        https://sspai.com/post/*
// @match        https://sspai.com/t/*
// @match        https://sspai.com/community
// @match        https://sspai.com/community/*
// @run-at       document-end
// @icon         https://www.google.com/s2/favicons?sz=64&domain=sspai.com
// @grant        unsafeWindow
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license      WTFPL
// ==/UserScript==

(async function() {
  'use strict';
  // TODO: article tag, emoji reaction

  const blockedUsers=new Set(GM_getValue('list',['tgwbddu0','5ayuq8jn','feverlife','o9azstw9','9hde6zq2','1ulv3hnm','4ea7t2zo','kiens',]))
  console.log('blocking users:',[...blockedUsers])

  GM_registerMenuCommand('配置屏蔽用户',()=>{
    const oldList=GM_getValue('list',[...blockedUsers])
    const input=prompt('请输入用户的主页地址,以逗号分隔',oldList.join(','))
    const list=input.split(',').map(s=>s.split(',')).flat()
    GM_setValue('list',list)
    alert('刷新后生效')
  })


  await waitFor(mounted)

  const vue=unsafeWindow.$vue

  filter()
  vue.$router.afterEach(()=>{
    setTimeout(filter,1000)
  })

  function filter(){
    console.log('开始过滤')
    const routes=vue.$router.getRoutes()
    const homePage=routes.find(r=>r.name==='home')?.instances.default
    const postPage=routes.find(r=>r.name==='article')?.instances.default
    const communityPage=routes.find(r=>r.name==='communityTopic')?.instances.default
    const communityHome=routes.find(r=>r.name==='communityHome')?.instances.default
    const community=routes.filter(r=>r.path.startsWith('/community')).find(r=>r.name===$vue.$route.name)?.instances.default

    // 首页文章列表
    if(homePage){
      homePage.$watch('articleListData', val=>{
        const newVal=val.filter(
          article=>{
            const shouldHide=blockedUsers.has(article.author?.slug)
            if(shouldHide)console.log(`blocked: ${article.title} by ${article.author.nickname}`)
            return !shouldHide
          }
        )
        if(newVal.length!==val.length) homePage.articleListData=newVal
      }, {immediate:true})
    }

    // 文章页
    if(postPage){
      // 文章评论区
      const commentsComp=postPage.$children.map(c=>c.$children).flat(Infinity).find(c=>c.$options.name==='comment')
      commentsComp.$watch('comments', val=>{
        const newVal=val.filter(
          comment=>{
            const newReplies=comment.reply?.filter(reply=>{
              const shouldHide=blockedUsers.has(reply.user.slug)
              if(shouldHide)console.log(`blocked: ${reply.comment} by ${reply.user.nickname}`)
              return !shouldHide
            })
            if(newReplies.length!==comment.reply?.length)comment.reply=newReplies

            const shouldHide=blockedUsers.has(comment.user?.slug)
            if(shouldHide)console.log(`blocked: ${comment.comment} by ${comment.user.nickname}`)
            return !shouldHide
          }
        )
        if(newVal.length!==val.length)commentsComp.comments=newVal
      }, {immediate:true})

      // 文章作者 页面标红
      if(blockedUsers.has(postPage.articleInfo.author.slug))mask()
    }

    // 社区主题内容
    if(communityPage){
      // 主题作者 页面标红
      if(blockedUsers.has(communityPage.userInfo.slug))mask()

      // 评论
      communityPage.$watch('comments', val=>{
        const newVal=val.filter(
          comment=>{
            const newReplies=comment.reply?.filter(reply=>{
              const shouldHide=blockedUsers.has(reply.author.slug)
              if(shouldHide)console.log(`blocked: ${reply.comment} by ${reply.author.nickname}`)
              return !shouldHide
            })
            if(newReplies.length!==comment.reply?.length)comment.reply=newReplies

            const shouldHide=blockedUsers.has(comment.author?.slug)
            if(shouldHide)console.log(`blocked: ${comment.comment} by ${comment.author.nickname}`)
            return !shouldHide
          }
        )
        if(newVal.length!==val.length)communityPage.comments=newVal
      }, {immediate:true})
    }

    // 社区主题列表
    if(community){
      community.$watch('collection', val=>{
        const newVal=val.filter(
          topic=>{
            const shouldHide=blockedUsers.has(topic.author?.slug)
            if(shouldHide)console.log(`blocked: ${topic.title} by ${topic.author.nickname}`)
            return !shouldHide
          }
        )
        if(newVal.length!==val.length)
          community.$store.commit('communityChannel/setCollection',{collection:newVal})
      }, {immediate:true})
    }
  }

  function mounted(){
    return unsafeWindow.$vue?._isMounted
  }

  function waitFor(check){
    return new Promise(ok=>{
      const id=setInterval(()=>{
        if(check()){
          clearInterval(id)
          ok()
        }
      },1000); // 篡改猴自带的编辑器在括号后看到分号才能正常缩进下一行
    })
  }

  function mask(){
    const div=document.createElement('div')
    div.style.width='100vw'
    div.style.height='100vh'
    div.style.position='fixed'
    div.style.top=0
    div.style.left=0
    div.style.zIndex=99 // 刚好不遮盖导航栏
    div.style.backgroundColor='darkred'

    document.body.appendChild(div)
  }
})();