Greasy Fork is available in English.

VK Ads Fixes

Script for blocking ads in VK (VKontakte), bypassing blocking detection, etc.

// ==UserScript==
// @name      VK Ads Fixes
// @name:ru      Правки рекламы ВКонтакте
// @name:uk      Правки реклами ВКонтакте
// @namespace    https://vtosters.app/
// @version      2.2
// @description Script for blocking ads in VK (VKontakte), bypassing blocking detection, etc.
// @description:ru Скрипт для блокировки рекламы в VK (ВКонтакте), обхода обнаружения блокировки и т.д.
// @description:uk Скрипт для блокування реклами у VK (ВКонтакті), обходу виявлення блокування тощо.
// @author       gdlbo, Vologhat
// @match        https://vk.com/*
// @match        https://vk.ru/*
// @grant        none
// ==/UserScript==

(() => {
    "use strict"

    class VkPeProperties
    {
        static #KEYS=[
            "send_user_info_stats", "force_send_user_info", "send_user_info_on_localhost",
            "send_navigation_stats_in_spa", "log_send_user_info_errors", "web_mytracker_collect_post_stats",
            "web_stats_device_id", "web_stats_reduce_debounce", "web_stats_send_beacon",
            "web_stats_send_on_events_limit", "web_stats_transport_story_view", "sentry_js_web_request_timeouts_feature",
            "sentry_js_web_request_timeouts_forwarding", "sentry_js_web_timeouts_forwarding", "sentry_js_web_verbose",
            "sentry_log_network_errors", "ads_app_form_link_redirect", "ads_autopromotion_web_geo",
            "ads_easy_promote_goods_new_create_api", "ads_light_methods_protection", "ads_market_autopromotion_bookmarks_stats",
            "ads_use_vk_community_video_portrait_4_5", "clips_web_my_tracker", "feed_post_track_code_client_web",
            "games_send_track_visitor_activity", "js_errors_no_write_uncaught_errors", "tgb_adblock_protection",
            "post_adblock_protection_promo", "eager_error_monitoring", "mini_apps_performance_close_app_empty_event",
            "mini_apps_performance_iframe_errors", "mini_apps_performance_web", "mini_apps_send_my_tracker_activity",
            "post_click_analytics_int_ext_link_click_web", "posting_track_event_count", "unique_adblock_users",
            "audio_my_tracker_web", "mini_apps_send_stat_arguments_bridge_events_sdk", "ajax_request_parse_html_error",
            "js_errors_no_write_uncaught_errors", "tns_track_sections", "tns_track_hosts", "geminus_counter",
            "ads_pixels_track_new_events_web_mvk", "web_navigation_handlers", "measure_module_navigation_stats",
            "group_join_track_event_count", "feed_content_events_open_post_event_web", "feed_posts_duration_stats_fix",
            "collect_unsupported_user_info_stats", "log_fetch_requests", "log_fetch_requests_get",
            "post_adguard_protection_promo", "extended_ajax_logging", "messenger_mediascope_stats_collect",
            "audio_player_stats_web"
        ];

        static isValidProperty(key)
        { return key in this.#KEYS }
    }

    //hook vk
    let actualVk=window.vk
    const vkHooks=new Set();
    Object.defineProperty(window,"vk", {
        get:() => actualVk,
        set:(value) => {
            actualVk=value
            if(actualVk)vkHooks.forEach( hook => hook(actualVk))
            return true
        },
        configurable:true
    })

    //hook vk properties
    const createAndPerformVkPropHook=(key,hookfn) => {
        //hook when vk redefines
        vkHooks.add(vk => {
            if(vk&&vk[key])hookfn(vk[key])
            
            //hook when property redefines
            let actualProp=vk[key]
            Object.defineProperty(vk,key, {
                get:() => actualProp,
                set:(value) => {
                    actualProp=value
                    hookfn(actualProp)
                    return true
                },
                configurable:true,
                enumerable:true
            })
        })
    }

    //remove properties from vk.pe hook
    createAndPerformVkPropHook("pe",pe => {
        console.log("patch pe")
        
        Object.keys(pe)
            .filter(key => VkPeProperties.isValidProperty(key))
            .forEach(key => delete window.vk.pe[key])
    })

    //patch vk.AudioAdsConfig hook
    createAndPerformVkPropHook("audioAdsConfig",audioAdsConfig => {
        console.log("patch audioAdsConfig")
        
        Object.defineProperties(audioAdsConfig, {
            enabled: {
                value:false
            },
            day_limit_reached: {
                value:false
            },
            sections: {
                value:[]
            }
        })
    })

    //disable error monitor DSN hook
    createAndPerformVkPropHook("cfg",cfg => {
        console.log("disable error monitoring DSN")
        
        Object.defineProperty(cfg.error_monitoring_config,"dsn", {
            value:"http://127.0.0.1"
        })
    })

    //patch vk.adParams hook
    createAndPerformVkPropHook("adParams",adParams => {
        console.log("patch adParams")
  
        Object.defineProperties(adParams, {
            ads_can_show: {
                value:0
            },
            leftads: {
                value:""
            },
            wsTransport: {
                value:"http://127.0.0.1"
            },
            ads_rotate_interval: {
                vallue:Number.MAX_SAFE_INTEGER
            }
        })
    })

    //trigger vk and properties hooks
    window.vk=window.vk

    setInterval(() => {
        //replace "away.php" url to the redirect url
        document.querySelectorAll("a[href*='away.php']")
            .forEach(a => {
                const url=URL.parse(a.href)
                if(!url.pathname.endsWith("away.php"))return
                //find a search parameter with valid redirect url
                url.searchParams.forEach((value) => {
                    if(URL.canParse(value))
                    {
                        a.href=value
                        return
                    }
                })
            })

        //remove _ads_block_data_w blocks
        document.querySelectorAll("div._ads_block_data_w")
            .forEach(div => {
                console.log(`Remove block with id ${div.id}]`)
                div.remove()
            })

        //remove ads_left block
        const adsLeft=document.getElementById("ads_left")
        if(adsLeft)
        {
            console.log("Remove block with id: ads_left")
            adsLeft.remove()
        }

        //clear all AdsLight functions
        if(window.AdsLight)
            Object.keys(window.AdsLight)
                .filter(key => typeof window.AdsLight[key]==="function")
                .forEach(key => Object.defineProperty(window.AdsLight,key, {
                    value:() => {}
                }))

        //patch window ads properties
        Object.defineProperties(window, {
            noAds: {
                value:true,
                configurable:true
            },
            noAdsAtAll: {
                value:true,
                configurable:true
            },
            no_left_ads: {
                value:true,
                configurable:true
            },
            no_ads: {
                value:true,
                configurable:true
            },
            isNoAdsForce: {
                value:true,
                configurable:true
            },
            hide_ad: {
                value:true,
                configurable:true
            },
            ya_direct: {
                value:false,
                configurable:true
            },
            yaDIrectAdActive: {
                value:false,
                configurable:true
            },
            __adsSet: {
                value:() => {},
                configurable:true
            },
            __adsUpdate: {
                value:() => {},
                configurable:true
            },
            AdmanHTML: {
                value:false,
                configurable:true
            },
            audioAdsConfig: {
                value:false,
                configurable:true
            },
            __adsGetAjaxParams: {
                value:() => {},
                configurable:true
            },
            __adsLoader: {
                value:() => {},
                configurable:true
            },
        })
    },30000/navigator.hardwareConcurrency)
})();