VK Ads Fixes

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

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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)
})();