yt blocker

none

// ==UserScript==
// @name         yt blocker
// @version      29
// @description  none
// @run-at       document-start
// @author       rssaromeo
// @license      GPLv3
// @match        *://youtube.com/*
// @match        *://*.youtube.com/*
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII=
// @grant        unsafeWindow
// @require https://update.greasyfork.org/scripts/491829/1356221/tampermonkey%20storage%20proxy.js
// @grant GM_getValue
// @grant GM_setValue
// @grant unsafeWindow
// @namespace https://greasyfork.org/users/1184528
// ==/UserScript==

// % of video watched to hide, 0 to not hide any
const hideWatchedVidProg = 1

const rclickBlocksUrl = true
const rclickBlocksTitle = true

const updateInterval = 1000

unsafeWindow.newJsData ??= []

// Intercept XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open
unsafeWindow.XMLHttpRequest.prototype.open = function (method, url) {
  // log(url)
  if (url.includes("youtube.com/youtubei/v1/player")) {
    const originalSend = this.send

    this.send = function (body) {
      this.addEventListener("load", function () {
        try {
          const responseData = JSON.parse(this.responseText)
          unsafeWindow.newJsData.push(responseData)
          console.log(
            "Intercepted YouTube player data:",
            responseData
          )
        } catch (e) {
          console.error("Failed to parse response data:", e)
        }
      })
      originalSend.call(this, body)
    }
  }
  originalOpen.call(this, method, url)
}

// Intercept fetch requests
const originalFetch = window.fetch
unsafeWindow.fetch = newfetch
var timerId = setInterval(() => {
  if (unsafeWindow.fetch != newfetch) {
    clearInterval(timerId)
    log("Intercepted fetch request:")
    unsafeWindow.fetch = newfetch
  }
})

function newfetch(...args) {
  const url = args[0]
  // log(url)
  if (
    (url?.url ?? url)?.includes?.("youtube.com/youtubei/v1/player")
  ) {
    return originalFetch.apply(this, args).then((response) => {
      const clone = response.clone() // Clone the response to read it
      clone
        .json()
        .then((data) => {
          unsafeWindow.newJsData.push(data)
          console.log(
            "Intercepted YouTube player data from fetch:",
            data
          )
        })
        .catch((e) => {
          console.error("Failed to parse fetch response data:", e)
        })
      return response // Return the original response
    })
  }
  return originalFetch.apply(this, args)
}
;(async () => {
  const a = loadlib("allfuncs")
  const sp = new storageproxy("globaloptions")
  var ls = sp.get()
  // var lastvol // stores the last volume to restore to when muting from sub button border
  var vidlock = true
  const LOC = {}
  updateLoc()

  // var LOADED = false
  function setVidSpeed() {
    unsafeWindow.novidspeedcontroller = true
    for (var vid of a.qsa("video")) {
      vid.playbackRate =
        vidlock || !unsafeWindow.ytInitialData
          ? 0
          : Number(!globalname ? 0 : localStorage.playrate ?? 0)
    }
  }
  ls.blockedCreators ??= []
  ls.blockedTitles ??= []
  ls.blockedTitlesReg ??= []
  ls.blockedCreatorsReg ??= []
  ls.blockedUrls ??= []
  if (LOC.watch) {
    var fastint = setInterval(setVidSpeed, 0)
    setVidSpeed()
    update()
    a.waituntil(() => globalname).then(()=>
    clearInterval(fastint))
  }
  setInterval(update, updateInterval)
  // LOADED = true
  var globalname
  function newBlockBtn(title, creator) {
    var elem = a.newelem("button", {
      innerHTML: ls.blockedCreators.includes(this.title)
        ? "unblock"
        : "block",
      creator,
      title,
      id: "blockbtn",
      onclick(e) {
        e.stopImmediatePropagation()
        e.stopPropagation()
        e.preventDefault()
        log(this.creator)
        if (ls.blockedCreators.includes(this.creator)) {
          ls.blockedCreators.splice(
            ls.blockedCreators.indexOf(this.creator),
            1
          )
        } else {
          ls.blockedCreators.push(this.creator)
        }
        update()
        log(ls.blockedCreators, this.creator)
      },
      oncontextmenu(e) {
        e.stopImmediatePropagation()
        e.stopPropagation()
        e.preventDefault()
        if (rclickBlocksUrl) {
          log(this.url)
          if (ls.blockedUrls.includes(this.url)) {
            ls.blockedUrls.splice(ls.blockedUrls.indexOf(this.url), 1)
          } else {
            ls.blockedUrls.push(this.url)
          }
          update()
          log(ls.blockedUrls, this.url)
        }
        if (rclickBlocksTitle) {
          log(this.title)
          if (ls.blockedTitles.includes(this.title)) {
            ls.blockedTitles.splice(
              ls.blockedTitles.indexOf(this.title),
              1
            )
          } else {
            ls.blockedTitles.push(this.title)
          }
          update()
          log(ls.blockedTitles, this.title)
        }
      },
    })
    ;((elem, creator) => {
      var val = creator
      Object.defineProperty(elem, "creator", {
        get() {
          return val
        },
        set(newval) {
          val = newval.replace(/ • \d+\w? views$/, "")
        },
        enumerable: true,
        configurable: true,
      })
    })(elem, creator)
    return elem
  }
  update()
  function update() {
    try {
      function getCreatorId(viddiv, url) {
        var id = a
          .qs(url, viddiv)
          .href.split("?v=")
          .at(-1)
          .split("&")[0]
        var video = findAllKeys(
          unsafeWindow.ytInitialData,
          "lockupMetadataViewModel"
        ).find((e) => findValue(e, id))
        var res = findKey(video, "browseEndpoint")?.browseId
        if (res) return res
        log(
          1111111,
          unsafeWindow.newJsData.find((e) => findValue(e, id))
        )
        if (LOC.watch || LOC.home){
          location.reload()
        }
        error(video, viddiv)
        return ''
      }
      updateLoc()
      unsafeWindow.ls = ls = sp.get()
      // log(LOC)
      if (LOC.search) {
        addVid(
          "div#dismissible.style-scope.ytd-video-renderer:has(a#video-title)",
          "a#video-title",
          "#video-title",
          getCreatorId,
          "#channel-info",
          "#text > a"
        )
      } else if (LOC.root) {
        globalname = null
        addVid(
          "ytd-rich-item-renderer:has(a>.cbCustomTitle):has(a.yt-core-attributed-string__link):has(yt-lockup-metadata-view-model)",
          "a:has(> .cbCustomTitle:first-child)",
          "a:has(> .cbCustomTitle:first-child)>*:not(.cbCustomTitle)",
          getCreatorId,
          "yt-lockup-metadata-view-model",
          "a.yt-core-attributed-string__link"
        )
        addVid(
          "ytd-rich-item-renderer:has(#content > yt-lockup-view-model > div > div > yt-lockup-metadata-view-model > div.yt-lockup-metadata-view-model-wiz__text-container > div > yt-content-metadata-view-model > div:nth-child(1) > span > span > a)",
          "#content > yt-lockup-view-model > div > a",
          "#content > yt-lockup-view-model > div > div > yt-lockup-metadata-view-model > div.yt-lockup-metadata-view-model-wiz__text-container > h3 > a > span.yt-core-attributed-string.yt-core-attributed-string--white-space-pre-wrap:not(.cbCustomTitle)",
          getCreatorId,
          "#content > yt-lockup-view-model > div > div > yt-lockup-metadata-view-model",
          "#content > yt-lockup-view-model > div > div > yt-lockup-metadata-view-model > div.yt-lockup-metadata-view-model-wiz__text-container > div > yt-content-metadata-view-model > div:nth-child(1) > span > span > a"
        )
      } else if (LOC.feed) {
        addVid(
          "ytd-rich-item-renderer:has(a>.cbCustomTitle):has(a.yt-core-attributed-string__link):has(yt-lockup-metadata-view-model)",
          "a:has(> .cbCustomTitle:first-child)",
          "a:has(> .cbCustomTitle:first-child)>*:not(.cbCustomTitle)",
          getCreatorId,
          "yt-lockup-metadata-view-model",
          "a.yt-core-attributed-string__link"
        )
        addVid(
          "#dismissible:has(#video-title-link)",
          "#video-title-link",
          "#video-title-link>yt-formatted-string:not(.cbCustomTitle)",
          getCreatorId,
          "#byline-container",
          "#container>#text-container>yt-formatted-string#text>a"
        )
        // ['contents']['twoColumnBrowseResultsRenderer']['tabs']['0']['tabRenderer']['content']['richGridRenderer']['contents']['5']['richItemRenderer']['content']['lockupViewModel']
      } else if (LOC.userhome || LOC.uservids) {
        const CREATOR = getCreatorNameFromUrl(location.href)
        const btn = a.qs(
          "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1 > #blockbtn"
        )
        if (
          a.qs(
            "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1"
          ) &&
          !btn
        ) {
          a.qs(
            "#page-header > yt-page-header-renderer > yt-page-header-view-model > div > div.page-header-view-model-wiz__page-header-headline > div > yt-dynamic-text-view-model > h1"
          ).appendChild(newBlockBtn(null, CREATOR))
        } else if (btn) {
          btn.innerHTML = isBlocked(btn.creator, btn.title, btn.url)
            ? "unblock - " +
              JSON.stringify(
                isBlocked(btn.creator, btn.title, btn.url)
              )
            : "block"
        }
        if (LOC.userhome) {
          addVid(
            "#dismissible:has(#video-title-link)",
            "#video-title-link",
            "#video-title-link",
            () => CREATOR,
            "#byline-container"
          )
          addVid(
            "#dismissible:has(#video-title-link)",
            "#video-title-link",
            "#video-title-link",
            (viddiv, url) => {
              var id = a
                .qs(url, viddiv)
                .href.split("?v=")
                .at(-1)
                .split("&")[0]
              var video = findAllKeys(
                unsafeWindow.ytInitialData,
                "lockupMetadataViewModel"
              ).find((e) => findValue(e, id))
              return (
                findKey(video, "browseEndpoint")?.browseId ??
                error(video, viddiv)
              )
            },
            "#byline-container",
            "#container>#text-container>yt-formatted-string#text"
          )
        }
        if (LOC.uservids) {
          addVid(
            "ytd-rich-item-renderer:has(#dismissible #video-title-link)",
            "#video-title-link",
            "#video-title-link > #video-title:not(.cbCustomTitle)",
            () => CREATOR,
            "#meta > h3"
          )
        }
      } else if (LOC.watch) {
        if (!a.qs("#playrate") && a.qs(".ytp-right-controls")) {
          a.qs(".ytp-right-controls").appendChild(
            a.newelem(
              "div",
              {
                display: "inline flex",
                flexDirection: "row",
                id: "playrate",
                class:
                  "ytp-button ytp-settings-button ytp-hd-quality-badge",
                width: "fit-content",
              },
              [
                a.newelem("button", {
                  innerHTML: ".1",
                  onclick() {
                    localStorage.playrate = 0.1
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: ".25",
                  onclick() {
                    localStorage.playrate = 0.25
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: "1",
                  backgroundColor: "#449",
                  onclick() {
                    localStorage.playrate = 1
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: "1.4",
                  onclick() {
                    localStorage.playrate = 1.4
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: "1.8",
                  onclick() {
                    localStorage.playrate = 1.8
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: "2",
                  backgroundColor: "#449",
                  onclick() {
                    localStorage.playrate = 2
                    update()
                  },
                }),
                a.newelem("button", {
                  innerHTML: "2.5",
                  onclick() {
                    localStorage.playrate = 2.5
                    update()
                  },
                }),
              ]
            )
          )
        }
        globalname =
          unsafeWindow.ytInitialData?.["contents"]?.[
            "twoColumnWatchNextResults"
          ]?.["results"]?.["results"]?.["contents"]?.["1"]?.[
            "videoSecondaryInfoRenderer"
          ]?.["subscribeButton"]?.["subscribeButtonRenderer"]?.[
            "channelId"
          ] ||
          unsafeWindow.ytInitialData?.["header"]?.[
            "pageHeaderRenderer"
          ]?.["content"]?.["pageHeaderViewModel"]?.["actions"]?.[
            "flexibleActionsViewModel"
          ]?.["actionsRows"]?.["0"]?.["actions"]?.["0"]?.[
            "subscribeButtonViewModel"
          ]?.["subscribeButtonContent"]?.["onTapCommand"]?.[
            "innertubeCommand"
          ]?.["subscribeEndpoint"]?.["channelIds"]
        //  a.qs(
        //   "#upload-info>ytd-channel-name#channel-name>#container>#text-container>yt-formatted-string#text > a"
        // )?.textContent
        if (
          a.qs("ytd-video-owner-renderer") &&
          a.qs("#title > h1 > span.cbCustomTitle") &&
          globalname
        ) {
          addVid(
            "ytd-watch-metadata",
            () => location.href.split("?v=").at(-1).split("&")[0],
            "#title > h1 > yt-formatted-string",
            () => {
              return globalname
            },
            "ytd-video-owner-renderer",
            "#container>#text-container>yt-formatted-string#text>a"
          )
          a.qs("ytd-watch-metadata").style.display = ""
          const btn = a.qs("ytd-video-owner-renderer>#blockbtn")
          vidlock = isBlocked(btn.creator, btn.title, btn.url)
          btn.innerHTML = isBlocked(btn.creator, btn.title, btn.url)
            ? "unblock - " +
              JSON.stringify(
                isBlocked(btn.creator, btn.title, btn.url)
              )
            : "block"
        }

        // these don't have creator id anywhere only creator name so all will be hidden

        // addVid(
        //   "ytd-compact-video-renderer:has(#dismissible #video-title-link)",
        //   "#video-title-link",
        //   "#container>#text-container>yt-formatted-string#text",
        //   "#metadata"
        // )
        // these also don't have creator data
        // addVid(
        //   "#movie_player > div.html5-endscreen.ytp-player-content.videowall-endscreen.ytp-show-tiles > div > a:has(span.ytp-videowall-still-info)",
        //   "span.ytp-videowall-still-info > span > span>div>.cbCustomTitle",
        //   "span.ytp-videowall-still-info > span > span>.ytp-videowall-still-info-author",
        //   "span.ytp-videowall-still-info > span > span>div"
        // )
        // new youtube display classes?

        addVid(
          "yt-lockup-view-model:has(yt-lockup-metadata-view-model)",
          ".yt-lockup-metadata-view-model__title",
          ".yt-lockup-metadata-view-model__title",
          getCreatorId,
          ".yt-lockup-metadata-view-model__text-container"
        )

        // log(video)
        // log()

        // a.qsa().forEach((e) => (e.style.visibility = "hidden"))
        // a.qsa(".ytp-videowall-still").forEach(
        //   (e) => (e.style.visibility = "hidden")
        // )
        // addVid(
        //   "yt-lockup-view-model:has(yt-lockup-metadata-view-model)",
        //   "div.yt-lockup-metadata-view-model-wiz__text-container > h3 > a",
        //   "yt-content-metadata-view-model > div:nth-child(1) > span",
        //   ".yt-lockup-view-model-wiz__metadata:has(yt-lockup-metadata-view-model)"
        // )
        setVidSpeed()
      }
    } catch (e) {
      trace("update", e)
    }
  }
  function findAllKeys(obj, keyToFind) {
    const results = []

    function recurse(currentObj) {
      for (const key in currentObj) {
        if (currentObj.hasOwnProperty(key)) {
          if (key.includes(keyToFind)) {
            results.push(currentObj[key]) // Add the path to results if it matches
          }

          if (
            typeof currentObj[key] === "object" &&
            currentObj[key] !== null
          ) {
            recurse(currentObj[key]) // Recur for nested objects
          }
        }
      }
    }

    recurse(obj, "")
    return results
  }
  function findAllValues(obj, keyToFind) {
    const results = []

    function recurse(currentObj) {
      for (const key in currentObj) {
        if (currentObj.hasOwnProperty(key)) {
          try {
            if (currentObj[key].includes(keyToFind)) {
              results.push(currentObj[key]) // Add the path to results if it matches
            }
          } catch (e) {}

          if (
            typeof currentObj[key] === "object" &&
            currentObj[key] !== null
          ) {
            recurse(currentObj[key]) // Recur for nested objects
          }
        }
      }
    }

    recurse(obj, "")
    return results
  }
  function findKey(obj, keyToFind) {
    const results = []

    function recurse(currentObj, exact = true) {
      if (results.length) {
        return results[0]
      }
      for (const key in currentObj) {
        if (currentObj.hasOwnProperty(key)) {
          if (exact ? key === keyToFind : key.includes(keyToFind)) {
            results.push(currentObj[key]) // Add the path to results if it matches
            return currentObj[key]
          }

          if (
            typeof currentObj[key] === "object" &&
            currentObj[key] !== null
          ) {
            recurse(currentObj[key]) // Recur for nested objects
          }
        }
      }
    }

    recurse(obj, "")
    return results[0]
  }
  function findValue(obj, keyToFind) {
    const results = []

    function recurse(currentObj, exact = true) {
      if (results.length) {
        return results[0]
      }
      for (const key in currentObj) {
        if (currentObj.hasOwnProperty(key)) {
          try {
            if (
              exact
                ? currentObj[key] === keyToFind
                : currentObj[key].includes(keyToFind)
            ) {
              results.push(currentObj[key]) // Add the path to results if it matches
              return currentObj[key]
            }
          } catch (e) {}

          if (
            typeof currentObj[key] === "object" &&
            currentObj[key] !== null
          ) {
            recurse(currentObj[key]) // Recur for nested objects
          }
        }
      }
    }

    recurse(obj, "")
    return results[0]
  }

  function addVid(
    mainDivID,
    url,
    titleID,
    creatorID,
    blockButtonParentID,
    // OLDurl,
    // OLDtitleID,
    OLDcreatorID
    // OLDblockButtonParentID
  ) {
    try {
      // log(mainDivID, a.qsa(mainDivID))
      // remove invalid block buttons on root
      // if (isroot())
      //   a.qsa("#blockbtn")
      //     .filter(function (btn) {
      //       return btn.closest(blockButtonParentID)
      //     })
      //     .forEach((e) => e.remove())
      function trycall(thing) {
        if (typeof thing === "function") {
          return thing(viddiv, url, titleID, creatorID) ?? ""
        }
        return undefined
      }
      for (var viddiv of a.qsa(mainDivID)) {
        if (viddiv.textContent.includes("Free with ads")) {
          viddiv.style.display = "none"
          continue
        }
        var btn = a.qs(blockButtonParentID + ">#blockbtn", viddiv)
        if (!btn)
          btn = a
            .qs(blockButtonParentID, viddiv)
            .appendChild(newBlockBtn("", ""))

        btn.url =
          trycall(url) ??
          a.qs(url, viddiv).href.split("?v=").at(-1).split("&")[0]
        btn.title =
          trycall(titleID) ??
          a.qs(titleID, viddiv).textContent.toLowerCase()
        btn.creator =
          trycall(creatorID) ??
          getCreatorNameFromUrl(a.qs(creatorID, viddiv).href)
        btn.innerHTML = ls.blockedCreators.includes(btn.creator)
          ? "unblock " + (btn.creator??"NO CREATOR SET")
          : "block "+(btn.creator??"NO CREATOR SET")
        var prog =
          a.qs(
            ".ytd-thumbnail-overlay-resume-playback-renderer.style-scope",
            viddiv
          ) ||
          a.qs(
            ".ytThumbnailOverlayProgressBarHostWatchedProgressBarSegment",
            viddiv
          )
        if (OLDcreatorID && btn.creator) {
          var OLDcreator =
            trycall(OLDcreatorID) ??
            getCreatorNameFromUrl(a.qs(OLDcreatorID, viddiv).href)
          delete OLDcreatorID
          ls.creatorNameDict ??= {}
          ls.creatorNameDict[btn.creator] ??= []
          if (!ls.creatorNameDict[btn.creator].includes(OLDcreator)) {
            ls.creatorNameDict[btn.creator].push(OLDcreator)
          }
          if (ls.blockedCreators.includes(OLDcreator)) {
            log(
              "UPDATING!!!",
              ls.blockedCreators[
                ls.blockedCreators.indexOf(OLDcreator)
              ],
              btn.creator
            )
            ls.blockedCreators[
              ls.blockedCreators.indexOf(OLDcreator)
            ] = btn.creator
          }
        }
        viddiv.style.display =
          isBlocked(btn.creator, btn.title, btn.url) ||
          (hideWatchedVidProg &&
            prog &&
            prog.style.width.replace("%", "") > hideWatchedVidProg)
            ? "none"
            : ""
      }
    } catch (e) {
      trace("addVid", e, titleID, creatorID, viddiv)
    }
  }
  unsafeWindow.isBlocked = isBlocked
  unsafeWindow.addVid = addVid
  function isBlocked(creator, title, url) {
    try {
      if (creator == undefined)
        return {
          type: "invalid creator",
          val: { creator, title, url },
        }

      if (ls.blockedUrls.includes(url))
        return { type: "blockedUrls", val: url }
      if (ls.blockedTitles.includes(title))
        return { type: "blockedTitles", val: title }
      if (ls.blockedCreators.includes(creator))
        return { type: "blockedCreators", val: creator }
      for (let reg of ls.blockedCreatorsReg) {
        if (new RegExp(reg, "i").test(creator))
          return { type: "blockedCreatorsReg", val: reg }
      }
      for (let reg of ls.blockedTitlesReg) {
        if (new RegExp(reg, "i").test(title))
          return { type: "blockedTitlesReg", val: reg }
      }
      return false
    } catch (e) {
      trace("isBlocked", e)
    }
  }
  function updateLoc() {
    Object.assign(LOC, {
      root: /^https?:\/\/(?:www\.)?youtube\.com\/?(?:\?|#|$)/.test(
        location.href
      ),
      watch:
        /^https?:\/\/(?:www\.)?youtube\.com\/watch\/?(?:\?|#|$)/.test(
          location.href
        ),
      search:
        /^https?:\/\/(?:www\.)?youtube\.com\/results\?search_query=.*(?:#|$)/.test(
          location.href
        ),
      feed: /^https?:\/\/(?:www\.)?youtube\.com\/feed\/subscriptions/.test(
        location.href
      ),
      userhome:
        /^https?:\/\/(?:www\.)?youtube\.com\/@[^\/]+\/?$/.test(
          location.href
        ),
      uservids:
        /^https?:\/\/(?:www\.)?youtube\.com\/@[^\/]+\/videos\/?$/.test(
          location.href
        ) ||
        /^https?:\/\/(?:www\.)?youtube\.com\/(?:channel|user|c)\/[^\/]+\/videos\/?$/.test(
          location.href
        ),
    })
  }
  unsafeWindow.getCreatorNameFromUrl = getCreatorNameFromUrl
  function getCreatorNameFromUrl(url) {
    return url.match(/(?:\/@|\/(?:channel|user|c)\/)([^\/]*)/i)?.[1]
  }
})()