纯净版斗鱼(pure douyu)

斗鱼纯净版,只保留直播和弹幕【斗鱼精简版、斗鱼极简版、斗鱼清爽版】

// ==UserScript==
// @name         纯净版斗鱼(pure douyu)
// @namespace    https://github.com/ljezio
// @version      4.4.6
// @author       ljezio
// @description  斗鱼纯净版,只保留直播和弹幕【斗鱼精简版、斗鱼极简版、斗鱼清爽版】
// @license      MIT
// @icon         https://www.douyu.com/favicon.ico
// @homepage     https://github.com/ljezio/pure-live
// @match        *://*.douyu.com/*
// @require      https://registry.npmmirror.com/vue/3.5.22/files/dist/vue.global.prod.js
// @grant        GM_addStyle
// ==/UserScript==

(function (vue) {
  'use strict';

  const d=new Set;const importCSS = async e=>{d.has(e)||(d.add(e),(t=>{typeof GM_addStyle=="function"?GM_addStyle(t):document.head.appendChild(document.createElement("style")).append(t);})(e));};

  importCSS(" .button[data-v-435d574d]{display:block;cursor:pointer;border:none;padding:0;background-color:transparent;opacity:.3;transition:opacity .3s ease}.button[data-v-435d574d]:hover{opacity:1}.draggable[data-v-cda9e461]{z-index:99999;position:fixed;cursor:move;padding:8px;background-color:transparent;-webkit-user-select:none;user-select:none} ");

  const restyleCss = "header,aside,.wm-general,.bc-wrapper,.RechangeJulyPopups,.IconCardAdBoundsBox,#js-bottom-left,#bc3,#bc3-bgblur,#js-player-dialog,#js-player-above-controller,#js-layout-fixed-buff,#js-room-top-banner,[class^=snapbar__],[class^=sidebar__],[class^=title__],[class^=interactive__],[class^=toggle__]{display:none!important}#root,#js-player-main{margin:0!important}[class^=stream__]{bottom:0!important;top:0!important}[class^=case__],[class^=playerWrap__],[class^=page__]{padding:0!important}#js-player-main:before,[class^=player__]:before{content:none!important}[class^=stream__]{height:100vh!important}[class^=fullScreenSendor-]{display:flex!important}";
  class SwitchFunction {
    #key;
    constructor(key) {
      this.#key = key;
    }
    isOn() {
      return !localStorage.getItem(this.#key);
    }
    switch() {
      if (this.isOn()) {
        localStorage.setItem(this.#key, "off");
      } else {
        localStorage.removeItem(this.#key);
      }
    }
  }
  const scriptSwitch = new SwitchFunction("pure_live_switch_script");
  const autoHighestImageSwitch = new SwitchFunction("pure_live_auto_highest");
  function throttle(fn, delay = 100) {
    let lastTime = 0;
    return function(...args) {
      const now = Date.now();
      if (now - lastTime > delay) {
        fn.apply(this, args);
        lastTime = now;
      }
    };
  }
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1 = ["title"];
  const _hoisted_2 = {
    viewBox: "0 0 1024 1024",
    xmlns: "http://www.w3.org/2000/svg",
    width: "20",
    height: "20"
  };
  const _hoisted_3 = ["fill"];
  const _hoisted_4 = { key: 0 };
  const _hoisted_5 = ["title"];
  const _hoisted_6 = {
    viewBox: "0 0 1024 1024",
    xmlns: "http://www.w3.org/2000/svg",
    width: "20",
    height: "20"
  };
  const _hoisted_7 = ["fill"];
  const onColor = "#2C9EFF";
  const offColor = "#D94A3C";
  const _sfc_main$2 = {
    __name: "ButtonGroup",
    setup(__props) {
      const scriptSwitchOn = vue.ref(scriptSwitch.isOn());
      const autoHighestImageSwitchOn = vue.ref(autoHighestImageSwitch.isOn());
      function switchScript() {
        scriptSwitchOn.value = !scriptSwitchOn.value;
        scriptSwitch.switch();
        location.reload();
      }
      function switchAutoHighestImage() {
        autoHighestImageSwitchOn.value = !autoHighestImageSwitchOn.value;
        autoHighestImageSwitch.switch();
      }
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createElementVNode("button", {
            class: "button",
            onClick: switchScript,
            title: scriptSwitchOn.value ? "关闭脚本" : "启用脚本"
          }, [
            (vue.openBlock(), vue.createElementBlock("svg", _hoisted_2, [
              vue.createElementVNode("path", {
                d: "M512.64 0C229.674667 0 0.298667 229.248 0.298667 512s229.376 512 512.384 512c282.965333 0 512.341333-229.248 512.341333-512S795.605333 0 512.64 0z m-37.290667 225.578667a38.528 38.528 0 0 1 77.141334 0v134.741333a38.528 38.528 0 0 1-77.141334 0V225.578667z m38.570667 578.773333a280.405333 280.405333 0 0 1-280.490667-280.277333 280.192 280.192 0 0 1 203.477334-269.312V323.413333a215.04 215.04 0 0 0 76.970666 415.829334 215.210667 215.210667 0 0 0 215.296-215.125334 215.04 215.04 0 0 0-138.282666-200.704V254.72c117.418667 33.493333 203.477333 141.269333 203.477333 269.312a280.362667 280.362667 0 0 1-280.448 280.32z",
                fill: scriptSwitchOn.value ? onColor : offColor
              }, null, 8, _hoisted_3)
            ]))
          ], 8, _hoisted_1),
          scriptSwitchOn.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4, [
            vue.createElementVNode("button", {
              class: "button",
              onClick: switchAutoHighestImage,
              title: autoHighestImageSwitchOn.value ? "关闭自动切换最高画质" : "开启自动切换最高画质"
            }, [
              (vue.openBlock(), vue.createElementBlock("svg", _hoisted_6, [
                vue.createElementVNode("path", {
                  d: "M0 0m256 0l512 0q256 0 256 256l0 512q0 256-256 256l-512 0q-256 0-256-256l0-512q0-256 256-256Z",
                  fill: autoHighestImageSwitchOn.value ? onColor : offColor
                }, null, 8, _hoisted_7),
                _cache[0] || (_cache[0] = vue.createElementVNode("path", {
                  d: "M752.4864 802.048a70.144 70.144 0 0 1-3.4816 0.1024H274.9952A70.144 70.144 0 0 1 204.8 731.9552V326.1952A70.2464 70.2464 0 0 1 274.944 256h474.112a68.9664 68.9664 0 0 1 33.0752 8.2432 70.9632 70.9632 0 0 1 27.136 25.856 73.3696 73.3696 0 0 1 7.8336 18.9952 75.1616 75.1616 0 0 1 2.0992 17.1008v405.76a70.3488 70.3488 0 0 1-43.3152 64.8704 74.24 74.24 0 0 1-16.5376 4.5568 69.2736 69.2736 0 0 1-6.8608 0.6656zM342.9888 392.5504a34.4576 34.4576 0 0 0-28.0576 12.4416 34.2016 34.2016 0 0 0-7.7312 21.6576v204.8a34.048 34.048 0 0 0 4.864 17.5616l0.8704 1.4336a34.9184 34.9184 0 0 0 15.36 12.5952 34.4576 34.4576 0 0 0 29.1328-1.4336 38.0928 38.0928 0 0 0 8.0384-5.9904 32.768 32.768 0 0 0 7.9872-12.6464 33.28 33.28 0 0 0 2.048-11.52V563.2h68.2496v68.2496a34.4576 34.4576 0 0 0 12.4416 26.4192 35.2256 35.2256 0 0 0 16.6912 7.3728 36.3008 36.3008 0 0 0 11.6224-0.3072 30.1056 30.1056 0 0 0 7.936-2.6112 39.2704 39.2704 0 0 0 7.0656-4.4544 33.9968 33.9968 0 0 0 12.4928-26.4192v-204.8a33.792 33.792 0 0 0-13.824-27.392 34.0992 34.0992 0 0 0-54.4256 27.392v68.3008H375.4496V426.6496a34.4576 34.4576 0 0 0-12.4416-26.368 34.2528 34.2528 0 0 0-19.968-7.68z m271.4112 0h-41.5232a26.6752 26.6752 0 0 0-26.7264 26.7264V640.2048a22.528 22.528 0 0 0 0.768 5.12 32.768 32.768 0 0 0 2.3552 6.144 28.16 28.16 0 0 0 6.656 8.0896 26.624 26.624 0 0 0 16.896 6.0416H614.4a139.008 139.008 0 0 0 45.9776-7.9872 135.68 135.68 0 0 0 63.6928-47.2064 144.5376 144.5376 0 0 0 13.7728-22.9888 135.9872 135.9872 0 0 0 7.168-97.9968 132.8128 132.8128 0 0 0-17.1008-36.1984 139.008 139.008 0 0 0-32.2048-33.792 133.632 133.632 0 0 0-35.328-18.944A138.24 138.24 0 0 0 614.4 392.6016z m3.3792 204.6976a66.6112 66.6112 0 0 1-3.3792 0.1024V460.8a67.84 67.84 0 0 1 50.6368 22.4256 69.12 69.12 0 0 1 17.3568 39.168 60.7744 60.7744 0 0 1 0 13.3632 66.304 66.304 0 0 1-7.7312 25.4976 67.8912 67.8912 0 0 1-46.9504 34.816 65.4336 65.4336 0 0 1-9.9328 1.1776z",
                  fill: "#FFFFFF"
                }, null, -1))
              ]))
            ], 8, _hoisted_5)
          ])) : vue.createCommentVNode("", true)
        ], 64);
      };
    }
  };
  const ButtonGroup = _export_sfc(_sfc_main$2, [["__scopeId", "data-v-435d574d"]]);
  const axisStorageKey = "pure_live_draggable_axis";
  const _sfc_main$1 = {
    __name: "Draggable",
    setup(__props) {
      const draggableE = vue.useTemplateRef("draggableRef");
      const isDragging = vue.ref(false);
      const axis = vue.reactive({ x: 0, y: 0, mouseX: 0, mouseY: 0 });
      function startDrag(event) {
        if (event.target !== draggableE.value) return;
        axis.mouseX = event.clientX;
        axis.mouseY = event.clientY;
        isDragging.value = true;
      }
      function onDrag(event) {
        if (!isDragging.value) return;
        setNewAxis(event.clientX - axis.mouseX + axis.x, event.clientY - axis.mouseY + axis.y);
        axis.mouseX = event.clientX;
        axis.mouseY = event.clientY;
      }
      function stopDrag() {
        isDragging.value = false;
        localStorage.setItem(
          axisStorageKey,
          JSON.stringify({ oldX: axis.x, oldY: axis.y, oldWidth: innerWidth, oldHeight: innerHeight })
        );
      }
      const beforeWidth = vue.ref(innerWidth);
      const beforeHeight = vue.ref(innerHeight);
      const resize = throttle(() => {
        setNewAxis(axis.x / beforeWidth.value * innerWidth, axis.y / beforeHeight.value * innerHeight);
        beforeWidth.value = innerWidth;
        beforeHeight.value = innerHeight;
      }, 100);
      function setNewAxis(newX, newY) {
        if (newX < 0) {
          axis.x = 0;
        } else if (newX > document.documentElement.clientWidth - draggableE.value.offsetWidth) {
          axis.x = document.documentElement.clientWidth - draggableE.value.offsetWidth;
        } else {
          axis.x = newX;
        }
        if (newY < 0) {
          axis.y = 0;
        } else if (newY > document.documentElement.clientHeight - draggableE.value.offsetHeight) {
          axis.y = document.documentElement.clientHeight - draggableE.value.offsetHeight;
        } else {
          axis.y = newY;
        }
      }
      vue.onBeforeMount(() => {
        const oldAxis = JSON.parse(localStorage.getItem(axisStorageKey));
        if (!oldAxis) return;
        axis.x = oldAxis.oldX / oldAxis.oldWidth * innerWidth;
        axis.y = oldAxis.oldY / oldAxis.oldHeight * innerHeight;
      });
      vue.onMounted(() => {
        document.addEventListener("mousemove", onDrag);
        document.addEventListener("mouseup", stopDrag);
        window.addEventListener("resize", resize);
      });
      vue.onUnmounted(() => {
        document.removeEventListener("mousemove", onDrag);
        document.removeEventListener("mouseup", stopDrag);
        window.removeEventListener("resize", resize);
      });
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock("div", {
          ref: "draggableRef",
          class: "draggable",
          style: vue.normalizeStyle({ left: axis.x + "px", top: axis.y + "px" }),
          onMousedown: startDrag
        }, [
          vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
        ], 36);
      };
    }
  };
  const Draggable = _export_sfc(_sfc_main$1, [["__scopeId", "data-v-cda9e461"]]);
  const _sfc_main = {
    __name: "Element",
    setup(__props) {
      const isShow = vue.ref(true);
      vue.onMounted(() => {
        document.addEventListener("fullscreenchange", handleShowButtonGroup);
      });
      vue.onUnmounted(() => {
        document.removeEventListener("fullscreenchange", handleShowButtonGroup);
      });
      function handleShowButtonGroup() {
        isShow.value = !document.fullscreenElement;
      }
      return (_ctx, _cache) => {
        return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", null, [
          vue.createVNode(Draggable, null, {
            default: vue.withCtx(() => [
              vue.createVNode(ButtonGroup)
            ]),
            _: 1
          })
        ], 512)), [
          [vue.vShow, isShow.value]
        ]);
      };
    }
  };
  function mountElement() {
    vue.createApp(_sfc_main).mount(
      (() => {
        const div = document.createElement("div");
        document.body.append(div);
        return div;
      })()
    );
  }
  function avoidSmallWindow() {
    const observer = new MutationObserver(() => {
      document.querySelector("#js-player-video-widgets .roomSmallPlayerFloatLayout-closeBtn")?.click();
      observer.disconnect();
    });
    observer.observe(document.querySelector("#js-player-video-case"), {
      attributes: true,
      attributeFilter: ["class", "style"]
    });
  }
  function autoHighestImage() {
    if (!autoHighestImageSwitch.isOn()) return;
    let times = 0;
    const highestImageInterval = setInterval(() => {
      if (times++ >= 10) {
        clearInterval(highestImageInterval);
        return;
      }
      const highestImageButton = document.querySelector(
        '#js-player-controlbar [class^="tipItem-"]:nth-child(2) li:first-child'
      );
      if (!highestImageButton) return;
      setTimeout(() => {
        if (!highestImageButton.className.startsWith("selected-")) {
          highestImageButton.click();
        }
      }, 3e3);
      clearInterval(highestImageInterval);
    }, 1e3);
  }
  function dbClick() {
    document.body.ondblclick = (event) => {
      event.stopPropagation();
      if (!document.fullscreenElement) {
        document.querySelector(
          '#js-player-controlbar [class^="right-"] > :last-child, #js-player-controlbar [class^="right__"] > :last-child'
        )?.click();
      } else {
        document.exitFullscreen().then();
      }
    };
  }
  (() => {
    if (!document.querySelector("#js-player-main")) return;
    mountElement();
    if (scriptSwitch.isOn()) {
      importCSS(restyleCss);
      avoidSmallWindow();
      autoHighestImage();
      dbClick();
    }
  })();

})(Vue);

QingJ © 2025

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