Remove Bot Comments

10/15/2022, 1:36:23 PM

// ==UserScript==
// @name        Remove Bot Comments
// @namespace   Violentmonkey Scripts
// @match       https://www.youtube.com/watch
// @grant       none
// @version     1.1
// @author      tikhiy
// @description 10/15/2022, 1:36:23 PM
// @license MIT
// ==/UserScript==

const THRESHOLD = 0.9

const AUTHORS = [
  `DONT READ MY PROFILE PICTURE`,
  `Kavetion`,
  `Savetion Xi`,
  `YeaMan`,
  `F?СК МЕ. ТАР 0N MY РIС`,
  `yuno hati`,
  `I’m subbing to everyone who subs to me`,
  `Mason`,
  `Don't Read Profile Photo`,
  `Woody Perfect`,
  `[redacted]`,
  `johnny1893`,
  `Mod M`,
  `Sleve McDichael`
]

const CONTENTS = [
  `I actually just made a script that removes this person and a few others from comment section. It works with Violentmonkey BETA extension. You should search Remove Bot Comments by TokyoRose on the Find scripts page`,
  `DONT READ MY USERNAME!`,
  `I’m better than Penguinz0`,
  `[Stop right there!!] Please ignore any bait replies such as "I'm better" "read my name" or anything that's offensive because they only want your attention. If you ignore them and not give them any views or attention then they will get bored and stop.`,
  `The music on my paige is better than charlie lol.`,
  `Pls,  rate my english in my last video, wanna some feedback from natives, im ukrainian and i dont have people around that can assess me`,
  `Whoever's reading this, I hope that whatever you're going through gets better and whatever you're struggling or worrying about will be fine and that everyone has a fantastic day! Amen`,
  `Dont_Read_My_Names`,
  `bro that's exactly how i feel istg girl called me a N-word and immediately regretted it vid on my chnnl`,
  `I know right?? Lmaoooo hilarious tbh`,
  `I meet PENGUINZ0 yesterday he shouted and did not agree to take a Picture with me! He should be banned!!!! Loved the comment`
]

const normalize = (() => {
    const VARIANTS = {
        0: /[߀]/g,
        " ": /[ ]/g,
        a: /[4ÀÁÂÃÄÅàáâãäåĀāĂ㥹ǍǎǞǟǺǻȀȁȂȃȺɑАаḀḁẚẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặⒶⓐⱥⱯAa]/g,
        aa: /[Ꜳꜳ]/g,
        ae: /[ÆæǢǣǼǽ]/g,
        ao: /[Ꜵꜵ]/g,
        au: /[Ꜷꜷ]/g,
        av: /[ꜸꜹꜺꜻ]/g,
        ay: /[Ꜽꜽ]/g,
        b: /[ƀƁƂƃɃɓБВбḄḅḆḇⒷⓑBb]/g,
        c: /[CÇçĆćĈĉČčƇƈȻȼСсḈḉↄⒸⓒꜾꜿCc]/g,
        d: /[ĎďĐđƉƊƋƌɖɗԁᏧᴅḌḍḎḏḐḑḒḓⒹⓓꞪDd]/g,
        dz: /[DždžDzdz]/g,
        e: /[ÈÉÊËèéêëĒēĔĕĘęĚěƎƐǝȄȅȆȇȨȩɇɛЕеᴇḔḕḖḗḘḙḚḛḜḝẸẹẺẻẼẽẾếỀềỂểỄễỆệⒺⓔEe]/g,
        f: /[ƑƒⒻⓕꝻꝼFf]/g,
        ff: /[ff]/g,
        ffi: /[ffi]/g,
        ffl: /[ffl]/g,
        fi: /[fi]/g,
        fl: /[fl]/g,
        g: /[ĜĝĞğĢģƓǤǥǦǧǴǵɠɢᵹḠḡⒼⓖꝽꝾꝿꞠꞡGg]/g,
        h: /[ĤĥĦħȞȟɥНнḤḥḦḧḨḩḪḫẖⒽⓗⱧⱨⱵⱶꞍHh]/g,
        hv: /[ƕ]/g,
        i: /[ÌÍÎÏìíîïĨĩĪīĬĭĮįıƗǏǐȈȉȊȋɨḬḭḮḯỈỉỊịⒾⓘIi]/g,
        j: /[ĴĵǰȷɈɉⒿⓙJj]/g,
        k: /[ĶķƘƙǨǩКкḰḱḲḳḴḵⓀⓚⱩⱪꝀꝁꝂꝃꝄꝅꞢꞣKk]/g,
        l: /[ĹĺĻļĽľĿŀŁłƚȽɫɭḶḷḸḹḺḻḼḽⓁⓛⱠⱡⱢꝆꝇꝈꝉꞀꞁLl]/g,
        lj: /[Ljlj]/g,
        m: /[ƜɯɱϻМмḾḿṂṃⓂⓜⱮMm]/g,
        n: /[ÑñŃńŅņŇňʼnƝƞǸǹȠɲИилԉᴎṆṇṈṉṊṋⓃⓝꞐꞑꞤꞥNn]/g,
        nj: /[Njnj]/g,
        o: /[ÒÓÔÕÖØòóôõöøŌōŎŏŐőƆƟƠơǑǒǪǫǬǭǾǿȌȍȎȏȪȫȬȭɔɵОо߀ᴑṌṍṎṏṐṑṒṓỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợⓄⓞꝊꝋꝌꝍOo]/g,
        oe: /[Œœ]/g,
        oi: /[Ƣƣ]/g,
        oo: /[Ꝏꝏ]/g,
        ou: /[Ȣȣ]/g,
        p: /[ƤƥρРрᵽṔṕⓅⓟⱣꝐꝑꝒꝓꝔꝕPp]/g,
        q: /[ɊɋⓆⓠꝖꝗꝘꝙQq]/g,
        r: /[ŔŕŖŗŘřȐȑȒȓɌɍɽГЯгяṚṛṜṝṞṟⓇⓡⱤꝚꝛꞂꞃꞦꞧRr]/g,
        s: /[ŚśŜŝŞşŠšȘșȿʂṢṣẞⓈⓢⱾꞄꞅꞨꞩSs]/g,
        t: /[ŢţŤťŦŧƬƭƮȚțȾʈТтṬṭṮṯṰṱẗⓉⓣⱦꞆꞇTt]/g,
        th: /[Þþ]/g,
        tz: /[Ꜩꜩ]/g,
        u: /[ÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųƯưǓǔǕǖǗǘǙǚǛǜȔȕȖȗɄʉПпṲṳṴṵṶṷṸṹṺṻỤụỦủỨứỪừỬửỮữỰựⓊⓤUu]/g,
        v: /[ƲɅʋʌṼṽṾṿⓋⓥꝞꝟVv]/g,
        vy: /[Ꝡꝡ]/g,
        w: /[ŴŵẀẁẂẃẄẅẈẉẘⓌⓦⱲⱳWw]/g,
        x: /[ХхẌẍⓍⓧXx]/g,
        y: /[ÝýÿŶŷŸƳƴȲȳɎɏУуẙỲỳỴỵỶỷỸỹỾỿⓎⓨYy]/g,
        z: /[ŹźŽžƵƶȤȥɀẐẑẒẓẔẕⓏⓩⱫⱬⱿꝢꝣZz]/g,
    }

    const VARIANTS_ENTRIES = Object.entries(VARIANTS)

    return (string) => {
        return VARIANTS_ENTRIES.reduce((result, [k, regex]) => {
            return result.replace(regex, k)
        }, string.toLowerCase())
    }
})()

const letters = (() => {
  const LETTERS = /[a-z]+/g

  return (string) => {
    return string.match(LETTERS).join("")
  }
})()

const compare = (a, b) => {
	if (a === b) {
    return 1
  }

	if (a.length < 2 || b.length < 2) {
    return 0
  }

	const bigrams = new Map()

	for (let i = 0; i < a.length - 1; i++) {
		const bigram = a.substring(i, i + 2)

		const count = bigrams.has(bigram)
			? bigrams.get(bigram) + 1
			: 1

		bigrams.set(bigram, count)
	};

	let intersection = 0

	for (let i = 0; i < b.length - 1; i++) {
		const bigram = b.substring(i, i + 2)

		const count = bigrams.has(bigram)
			? bigrams.get(bigram)
			: 0

		if (count > 0) {
			bigrams.set(bigram, count - 1)
			intersection++
		}
	}

	return (2 * intersection) / (a.length + b.length - 2)
}

const hasSimilar = (() => {
  function callback(sample) {
    return compare(sample, this) > THRESHOLD
  }

  return (array, value) => {
    return array.some(callback, value)
  }
})()

const AUTHORS_NORMALIZED = AUTHORS.map(normalize)
const AUTHORS_LETTERS = AUTHORS_NORMALIZED.map(letters)

const CONTENTS_NORMALIZED = CONTENTS.map(normalize)
const CONTENTS_LETTERS = CONTENTS_NORMALIZED.map(letters)

const observer = new MutationObserver((mutations, observer) => {
  const comments = new Set()

  for (const mutation of mutations) {
    if (!mutation.addedNodes.length) {
      continue
    }

    if (mutation.target.nodeName !== "YT-ICON") {
      continue
    }

    const closest = mutation.target.closest("ytd-comment-renderer")

    if (closest) {
      comments.add(closest)
    }
  }

  if (!comments.size) {
    return
  }

  for (const comment of comments) {
    const author = letters(normalize(comment.querySelector("#author-text").textContent))

    if (hasSimilar(AUTHORS_LETTERS, author)) {
      comment.remove()
    }

    const content = letters(normalize(comment.querySelector("#content-text").textContent))

    if (hasSimilar(CONTENTS_LETTERS, content)) {
      comment.remove()
    }
  }
})

const getTarget = (callback) => {
  return new Promise((resolve) => {
    const observer = new MutationObserver(() => {
      const target = callback()

      if (target) {
        observer.disconnect()
        resolve(target)
      }
    })

    observer.observe(document.querySelector("ytd-app"), { childList: true, subtree: true })
  })
}

getTarget(() => document.querySelector("#below ytd-item-section-renderer #contents")).then((contents) => {
  observer.observe(contents, { childList: true, subtree: true })
})

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址