吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1111|回复: 37
上一主题 下一主题
收起左侧

[其他原创] 【油猴脚本】抖音屏蔽直播

  [复制链接]
跳转到指定楼层
楼主
untitled15X 发表于 2026-10-4 00:21 回帖奖励
本帖最后由 untitled15X 于 2026-10-4 13:32 编辑

在网页版和pc客户端刷抖音刷一段时间就很卡,所以指挥AI开发了这个脚本。
在数据层拦截抖音网页版信息流中的直播条目,使直播卡片和播放器不会加载和渲染。可在油叉或脚本猫搜索“抖音屏蔽直播”快捷安装
[color=lab(34.924 0 0)]
功能特性
  • 数据层拦截:Hook 抖音网页版的 fetch / XMLHttpRequest 数据接口(推荐、精选、搜索、关注、用户主页等),在直播数据到达页面之前就把直播条目过滤掉
  • 直播完全不加载:直播卡片、直播播放器、直播流地址(flv 拉流)根本不会进入页面
  • 覆盖全场景:推荐信息流、精选页、关注页信息流、关注页 "正在直播" 列表、搜索页直播卡片
  • 不误伤普通视频:只删除被确认为直播的条目,普通视频、图集、用户信息全部保留
  • 直播间自动跳回首页:误入 live.douyin.com 或 /live/ 直播间地址时自动跳转
  • DOM 兜底:万一有漏网的直播标签("直播中" 角标)和直播入口,也会被隐藏
  • 兼容性好:同时 Hook fetch 与 XMLHttpRequest,适配抖音各种请求方式
使用声明
  • 无需任何配置,装完即用
  • 仅对抖音网页版生效(www.douyin.com / douyin.com 全站)
  • 卸载:在管理面板删除本脚本即可
免责声明
  • 本脚本仅用于个人学习与使用
  • 请遵守平台用户协议与相关法律法规
  • 脚本发布时功能在本机测试可用,不保证在其他设备或页面改版后依然有效
[color=lab(34.924 0 0)][backcolor=lab(95.4818 0.411302 -6.78529)]
[JavaScript] 纯文本查看 复制代码
// ==UserScript==
// @name         抖音屏蔽直播
// @namespace    DouyinUnlive
// @version      4.0.2
// @description  在数据层拦截抖音网页版信息流中的直播条目(推荐/精选/搜索/关注等接口),直播数据不进入页面,直播卡片和播放器完全不会创建和加载。
// @AuThor       Doubao
// @license      MIT
// @match        *://*.douyin.com/*
// @match        *://douyin.com/*
// @run-at       document-start
// @grant        none
// @noframes
// ==/UserScript==

(function () {
    'use strict';

    /* 自检标记:脚本成功运行后,<html> 标签会带有 data-dy-unlive="4.0.2",
     * 同时 window.__douyinUnlive 存在。若页面上没有这些标记,说明脚本未运行
     * (油猴未启用 / 脚本被禁用 / 装错浏览器),请先检查油猴管理面板。 */
    try {
        document.documentElement.setAttribute('data-dy-unlive', '4.0.2');
        window.__douyinUnlive = '4.0.2';
    } catch (e) { }

    /* =========================================================
     * 一、数据层拦截(主力):hook fetch / XHR,过滤直播条目
     *     直播数据根本到不了页面 -> 直播卡片/播放器不会渲染和加载
     * ========================================================= */

    var HIDDEN_ATTR = 'data-dy-unlive-hidden';
    var HOOKED = false;

    // 判断一个响应 URL 是否值得处理(抖音网页版数据接口)
    // 覆盖 aweme 系列(信息流/关注/搜索/直播卡片)、webcast(关注页正在直播列表)、
    // 以及所有 feed 接口;宽匹配防漏
    function shouldHandle(url) {
        if (!url) return false;
        return /aweme\/|webcast\/|\/feed\/|\/search\//i.test(url);
    }

    // 判断一个条目是不是直播(字段经真实抓包确认)
    // 注意:不要求 isEntry 前置,cell_room 是直播卡片专用字段,含它即直播
    function isLiveEntry(o) {
        if (!o || typeof o !== 'object' || Array.isArray(o)) return false;
        if ('cell_room' in o) return true;                            // 信息流直播卡片:内含直播房间数据+拉流地址(实测)
        if (o.aweme_type === 101) return true;                        // 信息流直播条目类型(实测)
        if ('rid' in o && 'live_status' in o) return true;            // 直播房间条目 webcast 接口(实测:live_reason 常为空串)
        if (o.live_reason) return true;                               // 直播原因字段(数字/字符串非空)
        if (o.is_live === true || o.is_live === 1 || o.is_live === '1') return true;
        if (o.live_info && typeof o.live_info === 'object' && Object.keys(o.live_info).length) return true;
        if (o.live_card && typeof o.live_card === 'object' && Object.keys(o.live_card).length) return true;
        if (o.room && typeof o.room === 'object' && Object.keys(o.room).length) return true;
        return false;
    }

    // 递归净化 JSON:仅删除直播条目,普通视频/用户/配置结构一律保留
    function sanitize(root) {
        if (Array.isArray(root)) {
            var kept = [];
            for (var i = 0; i < root.length; i++) {
                var it = root[i];
                if (it && typeof it === 'object' && !Array.isArray(it) && isLiveEntry(it)) {
                    continue; // 直播条目:删除
                }
                kept.push(sanitize(it));
            }
            return kept;
        }
        if (root && typeof root === 'object') {
            var keys = Object.keys(root);
            for (var k = 0; k < keys.length; k++) {
                root[keys[k]] = sanitize(root[keys[k]]);
            }
        }
        return root;
    }

    // 对响应文本做净化;不是 JSON 就原样返回
    function transformResponse(text) {
        var j;
        try { j = JSON.parse(text); } catch (e) { return text; }
        try {
            var cleaned = sanitize(j);
            var out = JSON.stringify(cleaned);
            return out.length <= text.length ? out : text; // 防异常膨胀
        } catch (e) { return text; }
    }

    // ---- hook fetch ----
    function hookFetch() {
        var origFetch = window.fetch;
        if (!origFetch) return;
        window.fetch = function () {
            var args = arguments;
            var url = (typeof args[0] === 'string') ? args[0] : (args[0] && args[0].url) || '';
            var p = origFetch.apply(this, args);
            if (!shouldHandle(url)) return p;
            return p.then(function (res) {
                try {
                    var ct = (res.headers && res.headers.get && res.headers.get('content-type')) || '';
                    if (ct && ct.indexOf('json') === -1) return res;
                    return res.clone().text().then(function (text) {
                        var out = transformResponse(text);
                        if (out === text) return res;
                        // 只保留 content-type,去掉 content-length / content-encoding 等
                        // 长度相关头,防止新 body 与旧头不一致导致前端解析失败
                        var headers = {};
                        if (ct) headers['content-type'] = ct;
                        return new Response(out, {
                            status: res.status,
                            statusText: res.statusText,
                            headers: headers
                        });
                    });
                } catch (e) { return res; }
            });
        };
    }

    // ---- hook XMLHttpRequest(兼容老请求方式)----
    function hookXHR() {
        var origOpen = XMLHttpRequest.prototype.open;
        var origSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.open = function (method, url) {
            this.__dyUrl = url;
            var xhr = this;
            // 在 open 阶段尽早注册,保证先于页面自身监听器改写 responseText
            this.addEventListener('readystatechange', function () {
                if (xhr.readyState !== 4) return;
                try {
                    var u = xhr.__dyUrl || '';
                    if (!shouldHandle(u)) return;
                    var rt = xhr.responseType || '';
                    if (rt && rt !== '' && rt !== 'text') return; // 非文本响应不处理
                    var text = xhr.responseText;
                    if (!text) return;
                    var out = transformResponse(text);
                    if (out === text) return;
                    Object.defineProperty(xhr, 'responseText', { get: function () { return out; }, configurable: true });
                    Object.defineProperty(xhr, 'response', { get: function () { return out; }, configurable: true });
                } catch (e) { }
            });
            return origOpen.apply(this, arguments);
        };
        XMLHttpRequest.prototype.send = function () {
            return origSend.apply(this, arguments);
        };
    }

    function installHooks() {
        if (HOOKED) return;
        HOOKED = true;
        try { hookFetch(); } catch (e) { }
        try { hookXHR(); } catch (e) { }
    }

    /* =========================================================
     * 二、直播间页面自动跳回首页
     * ========================================================= */

    function inLiveRoom() {
        return location.hostname === 'live.douyin.com' ||
            location.pathname.indexOf('/live/') !== -1;
    }

    if (inLiveRoom()) {
        location.replace('https://www.douyin.com/');
        return; // 直播页直接跳走,不装任何东西
    }

    /* =========================================================
     * 三、DOM 兜底层:数据层漏网时,隐藏直播卡片与直播入口
     *     (渲染后隐藏,仅作保底;正常情况下数据层已拦截,不会走到这里)
     *     注意:LivePlayer_PreCreatePlayer / douyin-player-loading 是
     *     普通视频播放器共用的组件,绝不能隐藏,否则会破坏视频播放。
     * ========================================================= */

    // CSS:隐藏直播标签、直播入口;不动任何视频播放组件
    var style = document.createElement('style');
    style.textContent = [
        '[data-e2e="user-info-living"] { display: none !important; }',
        '[data-e2e*="living" i] { display: none !important; }',
        'a[href*="live.douyin.com"] { display: none !important; }',
        '[aria-label*="直播" i] { display: none !important; }'
    ].join('\n');
    (document.head || document.documentElement).appendChild(style);

    function hide(el) {
        if (!el || el.nodeType !== 1) return;
        if (el.hasAttribute(HIDDEN_ATTR)) return;
        el.setAttribute(HIDDEN_ATTR, '1');
        el.style.setProperty('display', 'none', 'important');
    }

    // 找到直播卡片根并隐藏。
    // 实测:直播卡片根是 .discover-video-card-item 这类卡片容器(无 data-e2e),
    // 从直播标签(data-e2e="user-info-living")向上找 card-item / video-card / feed-item 特征容器。
    function hideLiveCardFrom(node) {
        var card = node;
        for (var i = 0; card && i < 10; i++) {
            var cls = (card.className || '').toString();
            if (/card-item|video-card|feed-item/i.test(cls)) break;
            card = card.parentElement;
        }
        if (!card || card === document.body) {
            card = node.closest ? (node.closest('[data-e2e]') || node) : node;
        }
        hide(card);
    }

    function scan(root) {
        if (!root || root.nodeType !== 1) return;
        var nodes;
        try {
            nodes = root.querySelectorAll('[data-e2e="user-info-living"], [data-e2e*="living" i]');
        } catch (e) { return; }
        for (var i = 0; i < nodes.length; i++) hideLiveCardFrom(nodes[i]);
    }

    // MutationObserver:新内容进场即查
    var observer = null;
    var pending = false;
    function attachObserver() {
        if (observer || !document.body) return;
        observer = new MutationObserver(function () {
            if (pending) return;
            pending = true;
            setTimeout(function () {
                pending = false;
                scan(document.body);
            }, 150);
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // 定时兜底:防 SPA 跳直播路由 + 定期复查
    setInterval(function () {
        if (inLiveRoom()) {
            location.replace('https://www.douyin.com/');
            return;
        }
        scan(document.body);
    }, 3000);

    /* =========================================================
     * 四、启动
     * ========================================================= */

    installHooks();           // document-start 尽早 hook,抢在页面请求前
    scan(document.documentElement);

    if (document.body) {
        attachObserver();
    } else {
        document.addEventListener('DOMContentLoaded', attachObserver);
    }

    console.info('[抖音屏蔽直播] 数据层拦截已启用');
})();



douyin-block-live.user.zip

4.46 KB, 下载次数: 84, 下载积分: 吾爱币 -1 CB

完整代码文件

免费评分

参与人数 2吾爱币 +4 热心值 +2 收起 理由
苏紫方璇 + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wanfon + 1 + 1 热心回复!

查看全部评分

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
lxdz443 发表于 2026-10-4 07:13
好用,感谢分享。
3#
alexccczxty555 发表于 2026-10-4 07:56
4#
HASU 发表于 2026-10-4 08:00
5#
dsarmf 发表于 2026-10-4 08:25
感谢分享。。。
6#
gao255255 发表于 2026-10-4 08:27
好东西,值得试试
7#
GHenmm 发表于 2026-10-4 08:49
这个好。谢谢分享
8#
天业电子 发表于 2026-10-4 09:07
这个实用。谢谢楼主
9#
zlqhysy 发表于 2026-10-4 09:30
直播带货的视频确实有点烦
10#
huaan1011 发表于 2026-10-4 09:50
可以屏蔽广告不?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-10-5 18:37

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表