youtube广告拦截

是拦截不是跳过也不是删除广告哦, 拦截所有youtube广告(播放页和首页)并且不留白哦,疑似是目前体验最好的

目前为 2023-11-22 提交的版本。查看 最新版本

// ==UserScript==
// @name         youtube广告拦截
// @namespace    http://tampermonkey.net/
// @version      1.0.8
// @description  是拦截不是跳过也不是删除广告哦, 拦截所有youtube广告(播放页和首页)并且不留白哦,疑似是目前体验最好的
// @author       hua
// @match        https://www.youtube.com/*
// @grant        unsafeWindow
// @run-at       document-start
// @license      MIT
// ==/UserScript==

//移除首页出现的短视频推荐栏 设置为true则移除 (无效)
// let remove_short_video = true

// // 移除首页出现的电影推荐栏  免费 Primetime 电影 设置为true则移除 (无效)
// let remove_movie_recommend_tab = true

// let remove_movie_recommend = true
let href
init()
navigation.addEventListener('navigate', () => {
    setTimeout(() => {
        url_change()
    }, 5)
});



function init() {
    href = location.href
    console.log('初始化开始!')
    let ytInitialPlayerResponse_value = unsafeWindow['ytInitialPlayerResponse']
    Object.defineProperty(unsafeWindow, 'ytInitialPlayerResponse', {
        get: function () {
            return ytInitialPlayerResponse_value
        },
        set: function (value) {
            obj_process(value, ["abs:playerAds=-", "abs:adPlacements=-", "abs:adBreakHeartbeatParams=-", 'abs:adSlots=-'])
            ytInitialPlayerResponse_value = value
        }
    });
    let ytInitialData_value = unsafeWindow['ytInitialData']
    Object.defineProperty(unsafeWindow, 'ytInitialData', {
        get: function () {
            return ytInitialData_value
        },
        set: function (value) {
            if (/watch/.test(href)) {
                obj_process(value, ['adSlotRenderer=-', 'relatedChipCommand.contents[*]=- /.compactMovieRenderer.badges[0].metadataBadgeRenderer.label~=含广告'], true)
                ytInitialData_value = value
            } else {
                obj_process(value, [{
                    "value": "richSectionRenderer=-",
                    "conditions": {
                        "value": ['/.content.richShelfRenderer.title.runs[0].text$text~=Shorts|电影|时下流行', '/.content.inlineSurveyRenderer.title.runs[0].text$text=你对这个视频有何看法?']
                    }
                }, 'masthead.adSlotRenderer=-',
                {
                    "value": "richGridRenderer.contents[*]=-",
                    "conditions": {
                        "value": ['/.richItemRenderer.content.videoRenderer.badges[0].metadataBadgeRenderer.label~=含广告', '/.richItemRenderer.content.adSlotRenderer$exist',"/.richSectionRenderer.content.statementBannerRenderer.title.runs[0].text~=歡迎試用|欢迎试用"],
                    }
                }], true)
                ytInitialData_value = value
            }
        }
    });
    const originFetch = fetch;
    unsafeWindow.fetch = (uri, options) => {
        async function fetch_request(response) {
            let url = response.url
            return_response = response
            if (url.indexOf('youtubei/v1/next') > 0) {
                const responseClone = response.clone();
                let result = await responseClone.text();
                result = text_process(result, ['adSlotRenderer=-', 'appendContinuationItemsAction.continuationItems[*]=- /.compactMovieRenderer.badges[0].metadataBadgeRenderer.label~=含广告','itemSectionRenderer.contents[*]=- /.compactMovieRenderer.badges[0].metadataBadgeRenderer.label~=含广告']
                    , 'insert', true)
                return_response = new Response(result, response);
            }
            if (url.indexOf('youtubei/v1/player') > 0) {
                const responseClone = response.clone();
                let result = await responseClone.text();
                result = text_process(result, ["abs:playerAds=-", "abs:adPlacements=-", "abs:adBreakHeartbeatParams=-", 'abs:dSlots=-']
                    , 'insert', true)
                return_response = new Response(result, response);
            }
            if (url.indexOf('youtubei/v1/browse') > 0) {
                const responseClone = response.clone();
                let result = await responseClone.text();
                result = text_process(result, ["richSectionRenderer=- /.content.richShelfRenderer.title.runs[0].text$text~=Shorts|电影|时下流行", {
                    'value': 'richItemRenderer=-',
                    'conditions': {
                        'value': ['/.content.videoRenderer.badges[0].metadataBadgeRenderer.label$text~=含广告', '/.content.adSlotRenderer$exist'],
                    }
                }]
                    , 'insert', true)
                return_response = new Response(result, response);
            }
            return return_response
        }

        return originFetch(uri, options).then(fetch_request);
    }
    console.log('初始化完成!')
}

function url_change() {
    if (location.href !== href) {
        console.log('网页url改变 href -> ' + location.href)
        href = location.href
    }
}

function text_process(data, values, mode, traverse_all) {
    mode = mode || 'cover'
    if (mode === 'reg') {
        for (let value of values) {
            let patten_express = value.split(SPLIT_TAG)[0]
            let replace_value = value.split(SPLIT_TAG)[1]
            let patten = new RegExp(patten_express, "g")
            data = data.replace(patten, replace_value)
        }
    }
    if (mode === 'cover') {
        data = values[0]
    }
    if (mode === 'insert') {
        traverse_all = traverse_all || false
        let json_data = JSON.parse(data)
        obj_process(json_data, values, traverse_all)
        data = JSON.stringify(json_data)
    }
    return data
}

function obj_process(json_obj, express_list, traverse_all = false) {
    let abs_path_info_list = []
    let abs_path_info_list_by_attr = []
    let abs_path_info_list_by_arr = []
    let relative_path_info_list = []
    let relative_path_list = []
    let relative_short_path_list = []

    function add_data_to_abs_path(path, operator, value, condition, array_index) {
        let tmp
        if (array_index !== "*") {
            tmp = {}
            path = path + (array_index ? '[' + array_index + ']' : '')
            tmp.path = path
            tmp.operator = operator
            tmp.value = value
            tmp.condition = condition
            if (array_index) {
                abs_path_info_list_by_arr.push(tmp)
            } else {
                abs_path_info_list_by_attr.push(tmp)
            }
            return
        }
        let array_length
        try {
            array_length = eval('path.length')
            if (!array_length) return
        } catch (error) {
            return
        }
        for (let tmp_index = array_length - 1; tmp_index >= 0; tmp_index--) {
            tmp = {}
            tmp.path = path + "[" + tmp_index + "]"
            tmp.operator = operator
            tmp.value = value
            tmp.condition = condition
            abs_path_info_list_by_arr.push(tmp)
        }
    }

    express_list.forEach(express => {
        let reg
        let express_type = typeof (express)
        let matchs
        let conditions
        let value
        reg = /^(abs:)?([a-zA-Z_0-9\.\*\[\]]*)((=\-|~=|=))(.*)?/
        if (express_type === 'string') {
            matchs = express.match(reg)
        } else {
            matchs = express.value.match(reg)
            conditions = express.conditions
        }
        let abs = matchs[1]
        let path = matchs[2]
        let operator = matchs[3]
        if (express_type === 'string') {
            let tmp_value = matchs[5] || ''
            let split_index = tmp_value.indexOf(' ')
            if (split_index > -1) {
                value = tmp_value.substring(0, split_index)
                conditions = tmp_value.substring(split_index + 1)
                conditions = {
                    'value': [conditions]
                }
            } else {
                value = tmp_value
            }
        }
        matchs = path.match(/\[(\*?\d*)\]$/)
        let array_index
        if (matchs) {
            path = path.replace(/\[(\*?\d*)\]$/, '')
            array_index = matchs[1]
        }
        if (abs) {
            add_data_to_abs_path('json_obj.' + path, operator, value, conditions, array_index)
        } else {
            relative_path_list.push(path)
            let tmp_short_path = path.split('.').pop()
            relative_short_path_list.push(tmp_short_path)
            relative_path_info_list.push({
                "path": path,
                "operator": operator,
                "value": value,
                "conditions": conditions,
                "array_index": array_index
            })
        }
    })
    if (relative_path_list.length > 0) {
        let dec_list = []
        let dec_index_list = []
        obj_property_traverse(json_obj, '', {
            "short_keys": relative_short_path_list,
            "real_keys": relative_path_list
        }, dec_list, dec_index_list, traverse_all)
        for (let i = 0; i < dec_index_list.length; i++) {
            let real_index = dec_index_list[i]
            let real_path_info = relative_path_info_list[real_index]
            let tmp_path = 'json_obj' + dec_list[i]
            add_data_to_abs_path(tmp_path, real_path_info.operator, real_path_info.value, real_path_info.conditions, real_path_info.array_index)
        }
    }
    abs_path_info_list = abs_path_info_list_by_attr.concat(abs_path_info_list_by_arr)
    for (let path_info of abs_path_info_list) {
        if (!obj_conditional(path_info, json_obj)) continue
        let operator = path_info.operator
        let path = path_info.path
        let value = path_info.value

        if (operator === '=-') {
            let math = path.match(/(.*)\[(\d+)\]$/)
            if (math) {
                let arr_express = math[1]
                let index = math[2]
                eval(arr_express + '.splice(' + index + ',1)')
                console.log('删除属性-->' + arr_express + '[' + index + ']', 0);
            } else {
                eval('delete ' + path)
                console.log('删除属性-->' + path, 0);

            }
        }
        if (operator === '~=') {
            let search_value = value.split(SPLIT_TAG)[0]
            let replace_value = value.split(SPLIT_TAG)[1]
            eval(path + '=' + path + '.replace(new RegExp(search_value, "g"), replace_value)')
        }
        if (operator === '=') {
            let type_ = eval('typeof (' + path + ')')
            if (type_ === 'number') value = Number(value)
            eval(path + '=value')
        }

    }

}

function obj_conditional(express_info, json_obj) {
    //json_obj 在eval里直接调用
    if (!express_info['condition']) return true
    let condition_infos = express_info['condition']
    // 与 
    for (let condition_list of Object.values(condition_infos)) {
        let result = false
        for (let condition of condition_list) {
            let reg = /^([a-zA-Z_0-9\/\.\[\]]*)?(.*)/
            let match = condition.match(reg)
            let condition_path = match[1]
            let conditional_express = match[2]
            if (condition_path.indexOf('/') === 0) {
                condition_path = express_info.path + condition_path.slice(1)
            }
            if (condition_path.indexOf('.') === 0) {
                let reg = /^\.+/
                let matchs = condition_path.match(reg)
                let tmp_paths = express_info.path.split('.')
                tmp_paths.length = tmp_paths.length - matchs[0].length
                condition_path = tmp_paths.join('.') + '.' + condition_path.replace(reg, '')
            }
            let condition_value
            try {
                condition_value = eval(condition_path)
            } catch (error) {
                continue
            }
            // if (typeof (condition_value) === 'object') condition_value = JSON.stringify(condition_value)
            result = value_conditional(condition_value, conditional_express)
            if (result) break

        }
        if (!result) return false
    }
    return true
}

function value_conditional(value, condition_express) {
    function excute_eval(express) {
        try {
            return eval(express)
        } catch (error) {
            return false
        }
    }

    let reg = /(\$text|\$value|\$exist)?((>=|<=|>|<|~=|=))?(.*)/
    let match = condition_express.match(reg)
    let condition_type = match[1] || '$text'
    let condition_operator = match[2]
    let condition_test_value = match[4]

    if (condition_type === '$value') {
        if (!['>=', '<=', '>', '<', '='].includes(condition_operator)) return false
        if (condition_operator === '=') condition_operator = '==='
        return excute_eval(value + condition_operator + condition_test_value)
    }
    if (condition_type === '$exist') {
        return excute_eval('value !== undefined && value !== null')
    }
    if (condition_type === '$text') {
        if (typeof (value) === 'object') value = JSON.stringify(value)
        if (['>=', '<=', '>', '<'].includes(condition_operator)) {
            return excute_eval(value.length + condition_operator + condition_test_value.length)
        }
        if (['=', '~='].includes(condition_operator)) {
            return condition_operator === '=' ? value === condition_test_value : new RegExp(condition_test_value).test(value)
        }
    }
    return false
}

function obj_property_traverse(obj, cur_path, dec_infos, dec_list, dec_index_list, traverse_all = false) {
    if (Array.isArray(obj)) {
        obj.forEach((tmp_obj, index) => {
            let tmp_path = cur_path + '[' + index + ']'
            if (!tmp_obj || typeof (tmp_obj) !== 'object') return
            obj_property_traverse(tmp_obj, tmp_path, dec_infos, dec_list, dec_index_list, traverse_all)
        })
        return
    }
    Object.keys(obj).forEach((key) => {
        let tmp_path = cur_path + '.' + key
        for (let i = 0; i < dec_infos["short_keys"].length; i++) {
            if (dec_infos["short_keys"][i] === key) {
                if (tmp_path.indexOf('.' + dec_infos["real_keys"][i]) > -1) {
                    dec_list.push(tmp_path)
                    dec_index_list.push(i)
                    if (traverse_all && typeof (obj[key]) === 'object') {
                        obj_property_traverse(obj[key], tmp_path, dec_infos, dec_list, dec_index_list, traverse_all)
                    }
                    return
                }
                break
            }
        }
        let value = obj[key]
        if (!value || typeof (value) !== 'object') return
        obj_property_traverse(value, tmp_path, dec_infos, dec_list, dec_index_list, traverse_all)
    })
}

QingJ © 2025

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