BetterBoyFriendTV

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

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

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

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==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);
  }
})();