Greasy Fork

Greasy Fork is available in English.

纯净版斗鱼(douyu)

斗鱼纯净版(douyu.com)。只保留直播和弹幕【斗鱼精简版、斗鱼极简版、斗鱼清爽版】;支持按钮切换关闭脚本;支持自动切换最高画质;

当前为 2025-09-26 提交的版本,查看 最新版本

// ==UserScript==
// @name         纯净版斗鱼(douyu)
// @namespace    https://github.com/ljezio
// @version      4.1.1
// @description  斗鱼纯净版(douyu.com)。只保留直播和弹幕【斗鱼精简版、斗鱼极简版、斗鱼清爽版】;支持按钮切换关闭脚本;支持自动切换最高画质;
// @homepage     https://github.com/ljezio/pure-douyu
// @author       ljezio
// @license      MIT
// @match        *://*.douyu.com/0*
// @match        *://*.douyu.com/1*
// @match        *://*.douyu.com/2*
// @match        *://*.douyu.com/3*
// @match        *://*.douyu.com/4*
// @match        *://*.douyu.com/5*
// @match        *://*.douyu.com/6*
// @match        *://*.douyu.com/7*
// @match        *://*.douyu.com/8*
// @match        *://*.douyu.com/9*
// @match        *://*.douyu.com/topic/*
// @match        *://*.douyu.com/beta/*
// @icon         https://www.douyu.com/favicon.ico
// @grant        none
// ==/UserScript==

const switchKey = 'pure_douyu_switch';
const autoHighestImageKey = 'pure_douyu_auto_highest';

(function () {
    'use strict';

    window.onload = () => {
        const buttonGroup = functionButtons();
        if (localStorage.getItem(switchKey)) return;
        removeNude()
            .then(() => autoFullWindow())
            .then(() => autoHighestImage());
        dbClick(buttonGroup);
        newNodeObserver();
    };
})();

/**
 * 功能按钮
 */
function functionButtons() {
    const buttonGroup = document.createElement('div');
    buttonGroup.style.cssText = 'z-index: 999; position: fixed; top: 0; right: 0;';
    document.body.appendChild(buttonGroup);
    // 开关脚本按钮
    const switchButton = document.createElement('button');
    switchButton.title = localStorage.getItem(switchKey) ? '启用脚本' : '关闭脚本';
    switchButton.innerHTML = `
        <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
            <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="#2C9EFF"/>
        </svg>
    `;
    switchButton.onclick = () => {
        if (localStorage.getItem(switchKey)) {
            localStorage.removeItem(switchKey);
        } else {
            localStorage.setItem(switchKey, 'off');
        }
        location.reload();
    };
    buttonGroup.appendChild(switchButton);
    if (!localStorage.getItem(switchKey)) {
        // 开关自动切换最高画质按钮
        const autoHighestImageButton = document.createElement('button');
        autoHighestImageButton.title = localStorage.getItem(autoHighestImageKey) ? '开启自动切换最高画质' : '关闭自动切换最高画质';
        autoHighestImageButton.innerHTML = `
            <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
                <path
                    d="M0 0m256 0l512 0q256 0 256 256l0 512q0 256-256 256l-512 0q-256 0-256-256l0-512q0-256 256-256Z"
                    fill="#2C9EFF"/>
                <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"/>
            </svg>
        `;
        autoHighestImageButton.onclick = () => {
            if (localStorage.getItem(autoHighestImageKey)) {
                autoHighestImageButton.title = '关闭自动切换最高画质';
                localStorage.removeItem(autoHighestImageKey);
            } else {
                autoHighestImageButton.title = '开启自动切换最高画质';
                localStorage.setItem(autoHighestImageKey, 'off');
            }
        };
        buttonGroup.appendChild(autoHighestImageButton);
    }
    // 按钮半透明样式与鼠标悬停透明度变化
    [...buttonGroup.children].forEach(button => {
        button.style.cssText = 'display: block; cursor: pointer; opacity: 0.5; transition: opacity 0.3s ease;';
        button.onmouseover = () => button.style.opacity = '1';
        button.onmouseout = () => button.style.opacity = '0.5';
    })
    return buttonGroup;
}

/**
 * 隐藏无用元素
 */
function removeNude() {
    return new Promise((resolve) => {
        const interval = setInterval(() => {
            if (!document.querySelector('[class^="sidebar__"]')) return;
            try {
                doRemoveNude();
            } finally {
                clearInterval(interval);
                resolve();
            }
        }, 500);
    });
}

function doRemoveNude() {
    setDisplayNone(document.querySelector('header'));
    document.querySelector('aside')?.remove();
    document.querySelectorAll('.wm-general')?.forEach(node => node.remove());
    document.querySelectorAll('.bc-wrapper ')?.forEach(node => node.remove());
    document.querySelector('[class^="snapbar__"]')?.remove();
    setDisplayNone(document.querySelector('[class^="sidebar__"]'));
    document.querySelector('[class^="title__"]')?.remove();
    document.querySelector('[class^="interactive__"]')?.remove();
    setDisplayNone(document.querySelector('#js-bottom-left'));
    document.querySelector('#bc3')?.remove();
    document.querySelector('#bc3-bgblur')?.remove();
    setDisplayNone(document.querySelector('#js-player-dialog'));
    setDisplayNone(document.querySelector('#js-player-above-controller'));
    // 修改样式
    const stream = document.querySelector('[class^="stream__"]');
    stream.style.bottom = '0';
    stream.style.top = '0';
    document.querySelector('[class^="case__"]').style.padding = '0';
    document.querySelector('#js-player-main').style.margin = '0';
    // 强制修改伪元素样式
    const style = document.createElement('style');
    style.textContent = `
        #js-player-main::before {
        content: none !important;
        }
        .${document.querySelector('[class^="player__"]').className.split(' ')[0]}::before {
        padding-top: 0 !important;
        padding-bottom: ${innerHeight - 16}px !important;
        }
    `;
    document.head.appendChild(style);
}

/**
 * 自动网页全屏
 */
function autoFullWindow() {
    return new Promise((resolve) => {
        const fullWindowInterval = setInterval(() => {
            // 自动网页全屏
            if (!fullWindow()) return;
            setTimeout(() => {
                setDisplayNone(document.querySelector('#js-layout-fixed-buff'));
                // 网页全屏可以输入弹幕
                const sideToggle = document.querySelector('[class^="toggle__"]');
                if (sideToggle) {
                    sideToggle.children[0]?.click();
                    setDisplayNone(sideToggle);
                }
            }, 10);
            clearInterval(fullWindowInterval);
            resolve();
        }, 300);
    })
}

/**
 * 自动切换最高画质
 */
function autoHighestImage() {
    if (localStorage.getItem(autoHighestImageKey)) return;
    let times = 0;
    const highestImageInterval = setInterval(() => {
        if (times++ >= 10) { // 小主播没有画质切换功能
            clearInterval(highestImageInterval);
            return;
        }
        const highestImageButton = document.querySelectorAll('[class^="tipItem-"]')[1]
            ?.children[1]?.children[0];
        if (!highestImageButton) return;
        setTimeout(() => {
            if (!highestImageButton.className.startsWith('selected-')) {
                highestImageButton.click();
            }
        }, 5000);
        clearInterval(highestImageInterval);
    }, 1000);
}

/**
 * 双击全屏
 */
function dbClick(buttonGroup) {
    document.body.ondblclick = event => {
        event.stopPropagation();
        const controlBar = document.querySelector('[class^="right-"]') ||
            document.querySelector('[class^="right__"]');
        if (!controlBar) return;
        const controlButtons = controlBar.childNodes;
        if (!document.fullscreenElement) {
            controlButtons[controlButtons.length - 1].click();
        } else {
            document.exitFullscreen().then();
        }
    };
    document.onfullscreenchange = () => {
        if (!document.fullscreenElement) {
            setTimeout(() => fullWindow(), 0);
            buttonGroup.style.display = 'block';
        } else {
            setDisplayNone(buttonGroup);
        }
    };
}

/**
 * 移除后增无用元素
 */
function newNodeObserver() {
    new MutationObserver(mutations => {
        for (let mutation of mutations) {
            if (mutation.type !== 'childList') {
                continue;
            }
            for (let node of mutation.addedNodes) {
                if (node.className === 'RechangeJulyPopups') {
                    node.remove();
                }
            }
        }
    }).observe(document.querySelector('body'), {childList: true})
}

/**
 * 网页全屏
 */
function fullWindow() {
    const controlBar = document.querySelector('[class^="right-"]') ||
        document.querySelector('[class^="right__"]');
    if (!controlBar) return false;
    const controlButtons = controlBar.childNodes;
    controlButtons[controlButtons.length - 2].click();
    return true;
}

/**
 * 隐藏元素
 */
function setDisplayNone(node) {
    if (!node) return;
    node.style.display = 'none';
}