BetterBoyFriendTV

优化 BoyFriendTV 浏览体验:去除导航栏广告、直播卡片、底栏与边栏冗余区块。

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         BetterBoyFriendTV
// @namespace    BetterGayPornSites
// @version      0.1.5
// @author       AtmoOmen
// @description  优化 BoyFriendTV 浏览体验:去除导航栏广告、直播卡片、底栏与边栏冗余区块。
// @match        https://www.boyfriendtv.com/*
// @match        https://boyfriendtv.com/*
// @run-at       document-start
// @license      MIT
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function () {
  "use strict";

  const FEATURES = {
    nav: { key: "betterBftvNav", label: "精简导航栏" },
    topbar: { key: "betterBftvTopbar", label: "精简顶栏" },
    live: { key: "betterBftvLive", label: "精简视频流" },
    footer: { key: "betterBftvFooter", label: "精简底栏" },
    sidebar: { key: "betterBftvSidebar", label: "精简边栏" },
    float: { key: "betterBftvFloat", label: "精简浮动组件" },
    player: { key: "betterBftvPlayer", label: "精简视频播放" },
  };

  const state = {};
  const commandIds = {};
  let bannerPatched = false;
  let menuRetries = 0;

  const loadValue = (key, fallback) => {
    try {
      return GM_getValue(key, fallback);
    } catch (e) {
      return fallback;
    }
  };

  for (const name in FEATURES) {
    state[name] = loadValue(FEATURES[name].key, true);
  }

  const normalize = (value) => (value || "").replace(/\s+/g, " ").trim();

  function cleanNav() {
    for (const item of document.querySelectorAll("ul.navmenu > li")) {
      const link = item.querySelector(":scope > a");
      if (link && ["Live Sex", "AI Lover", "Creators"].includes(normalize(link.textContent))) {
        item.remove();
      }
    }
  }

  function cleanLive() {
    for (const tile of document.querySelectorAll("li.mtile-x7")) {
      const isLive =
        tile.querySelector('a[href*="/link/out/cam"]') !== null ||
        [...tile.querySelectorAll(".js-rating-text-percent")].some((el) => normalize(el.textContent) === "LIVE");
      if (isLive) {
        tile.remove();
      }
    }
    for (const tile of document.querySelectorAll("div.content-item.video-item-wrapper")) {
      const isLive =
        tile.querySelector('a[href*="/link/out/cam"]') !== null ||
        [...tile.querySelectorAll(".content-rating")].some((el) => normalize(el.textContent) === "LIVE");
      if (isLive) {
        tile.remove();
      }
    }
    if (document.body && document.body.classList.contains("js-mobile")) {
      for (const frame of document.querySelectorAll('iframe[src*="janusaent.com/widgets"], iframe[src*="mob-foot.html"]')) {
        const box = frame.closest(".box-listing");
        if (box) {
          box.remove();
        } else {
          const block = frame.closest(".content-block");
          if (block) {
            block.remove();
          }
        }
      }
    }
    for (const heading of document.querySelectorAll("h2.amateur-promo-heading")) {
      if (normalize(heading.textContent).toLowerCase() === "best creator videos") {
        const list = heading.nextElementSibling;
        heading.remove();
        if (list && list.classList.contains("ast-model-promo-list")) {
          list.remove();
        }
      }
    }
  }

  function cleanTopbar() {
    const labels = ["Follow us @ Twitter", "Shemale Porn", "Fetish Porn", "Premium Male Access"];
    for (const item of document.querySelectorAll("ul.pull-left.topmenu > li")) {
      const link = item.querySelector(":scope > a");
      if (link && labels.includes(normalize(link.textContent))) {
        item.remove();
      }
    }
    const mobileLabels = ["AI Boys", "Pornstars", "Creators", "Porn AI"];
    for (const item of document.querySelectorAll("ul.top-links-menu > li")) {
      const link = item.querySelector(":scope > a");
      if (link && mobileLabels.includes(normalize(link.textContent))) {
        item.remove();
      }
    }
  }

  function cleanFloat() {
    for (const el of document.querySelectorAll("#js-chat-bubble, .chat-bubble, #js-chat-panel")) {
      el.remove();
    }
  }

  function patchBannerManager() {
    if (bannerPatched) {
      return;
    }
    let manager = window.CookieManager;
    Object.defineProperty(window, "CookieManager", {
      configurable: true,
      get() {
        return manager;
      },
      set(value) {
        manager = value;
        if (value && typeof value.getBannerDisplayed === "function") {
          const originalGetBanner = value.getBannerDisplayed;
          value.getBannerDisplayed = function (key) {
            if (key === "schat") {
              return true;
            }
            return originalGetBanner.call(this, key);
          };
        }
      },
    });
    window.CookieManager = manager;
    bannerPatched = true;
  }

  function cleanPlayer() {
    patchBannerManager();
    const isPlayerArea = (el) =>
      el && (el.id === "mediaplayer_wrapper" || el.id === "video-details" || el.classList.contains("video-detail") ||
        el.querySelector("#mediaplayer_wrapper, #video-details, .video-detail") !== null);
    for (const overlay of document.querySelectorAll(".az6-overlay")) {
      overlay.remove();
    }
    if (document.body) {
      document.body.classList.remove("az6-overlay-shown");
    }
    if (!location.pathname.startsWith("/videos/")) {
      return;
    }
    for (const ad of document.querySelectorAll("a.ads-stripchat-link")) {
      const item = ad.parentElement && ad.parentElement.tagName === "LI" ? ad.parentElement : ad.closest("li");
      if (item && !isPlayerArea(item)) {
        item.remove();
      } else if (!isPlayerArea(ad)) {
        ad.remove();
      }
    }
    const rightside = document.querySelector(".rightside2");
    if (rightside && !isPlayerArea(rightside)) {
      rightside.remove();
      const main = document.querySelector("#maincolumn2");
      if (main) {
        main.classList.remove("has-right-ads");
      }
    }
    for (const block of document.querySelectorAll(".info-block-wrapper")) {
      if (!isPlayerArea(block)) {
        block.remove();
      }
    }
    for (const wrapper of document.querySelectorAll(".zn-wrapper")) {
      if (!isPlayerArea(wrapper)) {
        wrapper.remove();
      }
    }
    for (const script of document.querySelectorAll("script")) {
      if (/fh-wgt\.com|FapHouse/i.test(script.textContent)) {
        const host = script.previousElementSibling;
        if (host && host.tagName === "DIV" && !isPlayerArea(host)) {
          host.remove();
        }
        script.remove();
      }
    }
    for (const label of document.querySelectorAll(".zn-label")) {
      const host = label.closest("div");
      if (host && !isPlayerArea(host)) {
        host.remove();
      }
    }
    for (const ad of document.querySelectorAll("a.q1-line, a.below-video-link")) {
      const host = ad.parentElement;
      if (host && host.tagName === "DIV" && !isPlayerArea(host)) {
        host.remove();
      } else if (!isPlayerArea(ad)) {
        ad.remove();
      }
    }
  }

  function cleanFooter() {
    const headings = [
      "Videos of BoyFriendTV Creators",
      "Last commented models",
      "Chat with LIVE models",
      "Last commented videos",
    ];
    for (const wrapper of document.querySelectorAll(".js-toggle-content-wrapper")) {
      const menu = wrapper.querySelector(".js-toggle-content-menu");
      if (menu && headings.some((heading) => normalize(menu.textContent).startsWith(heading))) {
        wrapper.remove();
      }
    }
    for (const wrapper of document.querySelectorAll(".js-toggle-content-wrapper.block-amateur")) {
      wrapper.remove();
    }
    for (const heading of document.querySelectorAll("#main-v6 > div.vtab")) {
      const block = heading.nextElementSibling;
      if (block && block.classList.contains("content-block") && block.classList.contains("default-padding")) {
        heading.remove();
        block.remove();
      }
    }
    for (const heading of document.querySelectorAll("h3")) {
      if (normalize(heading.textContent).startsWith("Chat with LIVE models")) {
        const container = heading.parentElement;
        if (container && container.classList.contains("container")) {
          container.remove();
        }
      }
    }
  }

  function cleanSidebar() {
    for (const title of document.querySelectorAll(".left-menu-box-title")) {
      const text = normalize(title.textContent);
      if (text === "Recommended") {
        const block = title.closest(".left-menu-box");
        if (block) {
          block.remove();
        }
      } else if (text === "Top Creators" || text === "Top Pornstars") {
        const sibling = title.nextElementSibling;
        title.remove();
        if (sibling && (sibling.tagName === "DIV" || sibling.tagName === "UL")) {
          sibling.remove();
        }
      }
    }
    const tagsBlock = [...document.querySelectorAll(".left-menu-box")].find(
      (box) => box.querySelector(":scope > .left-menu-box-title") &&
        normalize(box.querySelector(":scope > .left-menu-box-title").textContent) === "Tags"
    );
    if (tagsBlock) {
      const homeList = [...tagsBlock.querySelectorAll("ul.left-menu-box")].find((list) =>
        [...list.querySelectorAll("a")].some((link) => normalize(link.textContent) === "Home")
      );
      if (homeList) {
        for (const item of [...homeList.children]) {
          const link = item.querySelector(":scope > a");
          if (!link) {
            continue;
          }
          const text = normalize(link.textContent);
          if (link.querySelector('img[alt="Country flag"]') || text === "Creators" || text === "Live Cam Models") {
            item.remove();
          }
        }
      }
    }
    const mobileLabels = ["Creators' Videos", "Pornstars", "Creators", "Live Cam Models", "Live Sex"];
    for (const item of document.querySelectorAll("div.navmenu.navbar-default > ul.navmenu-nav > li")) {
      const link = item.querySelector(":scope > a");
      if (link && mobileLabels.includes(normalize(link.textContent))) {
        item.remove();
      }
    }
    if (document.body && document.body.classList.contains("js-mobile")) {
      for (const item of document.querySelectorAll(".trending-tags > li")) {
        const link = item.querySelector(":scope > a");
        if (link && link.querySelector('img[alt="Country flag"]')) {
          item.remove();
        }
      }
    }
  }

  function clean() {
    if (state.nav) {
      cleanNav();
    }
    if (state.topbar) {
      cleanTopbar();
    }
    if (state.live) {
      cleanLive();
    }
    if (state.footer) {
      cleanFooter();
    }
    if (state.sidebar) {
      cleanSidebar();
    }
    if (state.float) {
      cleanFloat();
    }
    if (state.player) {
      cleanPlayer();
    }
  }

  function registerMenus() {
    try {
      for (const name in FEATURES) {
        const feature = FEATURES[name];
        if (commandIds[name] != null) {
          GM_unregisterMenuCommand(commandIds[name]);
        }
        commandIds[name] = GM_registerMenuCommand(`${feature.label}:${state[name] ? "开" : "关"}`, () => {
          state[name] = !state[name];
          GM_setValue(feature.key, state[name]);
          registerMenus();
          clean();
        });
      }
    } catch (e) {
      menuRetries += 1;
      if (menuRetries < 20) {
        setTimeout(registerMenus, 500);
      }
    }
  }

  let scheduled = false;
  const observer = new MutationObserver(() => {
    if (scheduled) {
      return;
    }
    scheduled = true;
    setTimeout(() => {
      scheduled = false;
      clean();
    }, 0);
  });

  function start() {
    registerMenus();
    clean();
    observer.observe(document.documentElement, { childList: true, subtree: true });
    document.addEventListener(
      "click",
      (e) => {
        if (!state.player) {
          return;
        }
        const target = e.target;
        if (!target || typeof target.closest !== "function") {
          return;
        }
        const pop = target.closest(".js-pop");
        if (pop && pop.querySelector("a[href]")) {
          e.stopPropagation();
        }
      },
      true
    );
    window.addEventListener("pageshow", clean);
    document.addEventListener("DOMContentLoaded", clean);
    window.addEventListener("load", clean);
    setTimeout(clean, 1000);
    setTimeout(clean, 3000);
  }

  if (document.documentElement) {
    start();
  } else {
    document.addEventListener("DOMContentLoaded", start);
  }
})();