Bypasses ads on ALL GameVui.vn games by patching the ad SDK before it loads
// ==UserScript==
// @name ZeroAd: GameVui
// @namespace https://greasyfork.org/users/zeroadv6
// @version 6.0.0
// @description Bypasses ads on ALL GameVui.vn games by patching the ad SDK before it loads
// @author ZeroAd Team
// @match *://*.gamevui.vn/*
// @match *://gamevui.vn/*
// @grant none
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const DEBUG = false;
const log = (...args) => DEBUG && console.log('[ZeroAd:GameVui]', ...args);
// The callback‑triggering stub we will inject into every ad function
const AD_STUB = `(function(){var _cb=arguments[0];if(typeof _cb==='function'){setTimeout(_cb,10);}})`;
/**
* Patch a script's text content – replace every known ad‑trigger function
* with a stub that immediately calls its success callback.
*/
function patchScriptText(originalText) {
// Replace GVAdBreak(callback) -> stub(callback)
// This handles both plain calls and any obfuscated variations.
return originalText
.replace(/GVAdBreak\s*\(/g, `${AD_STUB}(`)
.replace(/showVideoAD\s*\(/g, `${AD_STUB}(`)
.replace(/\.playAd\s*\(/g, `.${AD_STUB}(`); // common ad method
}
// 1. Intercept XMLHttpRequest – used to load external ad scripts
const XHR = XMLHttpRequest.prototype;
const origOpen = XHR.open;
XHR.open = function(method, url, ...rest) {
const urlStr = String(url).toLowerCase();
// Heuristic: any URL containing "ad", "sdk", or "gvad" is probably the ad script
if (/\/ad[s]?\//.test(urlStr) || /\/sdk\//.test(urlStr) || /gvad/i.test(urlStr)) {
log('Intercepting XHR to ad SDK:', url);
this._za_intercepted = true;
this._za_url = url;
}
return origOpen.call(this, method, url, ...rest);
};
const origSend = XHR.send;
XHR.send = function(body) {
if (this._za_intercepted) {
const origOnReady = this.onreadystatechange;
this.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
log('Patching ad SDK response from:', this._za_url);
const patched = patchScriptText(this.responseText);
// Override response data
Object.defineProperty(this, 'response', { value: patched });
Object.defineProperty(this, 'responseText', { value: patched });
// Trigger the original handler with the patched data
if (origOnReady) origOnReady.call(this);
} else if (origOnReady) {
origOnReady.call(this);
}
};
}
return origSend.call(this, body);
};
// 2. Intercept fetch – modern replacement for XHR
const origFetch = window.fetch;
window.fetch = function(input, init) {
const url = typeof input === 'string' ? input : input.url;
const urlLower = url.toLowerCase();
if (/\/ad[s]?\//.test(urlLower) || /\/sdk\//.test(urlLower) || /gvad/i.test(urlLower)) {
log('Intercepting fetch to ad SDK:', url);
return origFetch.call(this, input, init).then(async response => {
if (!response.ok) return response;
const text = await response.text();
const patched = patchScriptText(text);
// Create a new Response with the patched body
return new Response(patched, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
});
}
return origFetch.call(this, input, init);
};
// 3. Intercept <script> tag creation (catches scripts added dynamically)
const origSetSrc = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src').set;
Object.defineProperty(HTMLScriptElement.prototype, 'src', {
set: function(value) {
const urlLower = String(value).toLowerCase();
if (/\/ad[s]?\//.test(urlLower) || /\/sdk\//.test(urlLower) || /gvad/i.test(urlLower)) {
log('Blocking script src with ad pattern:', value);
// Instead of loading the real script, we load a tiny in‑memory stub
// that does nothing harmful. (We don't even need to fetch it.)
this._za_originalSrc = value;
// Prevent default loading
return;
}
return origSetSrc.call(this, value);
},
configurable: true
});
// 4. Fallback: property trap on window.GVAdBreak (in case it's still set directly)
let _GVAdBreak = window.GVAdBreak;
Object.defineProperty(window, 'GVAdBreak', {
configurable: true,
enumerable: true,
get() { return _GVAdBreak; },
set(val) {
if (typeof val === 'function') {
log('GVAdBreak assigned – replacing with stub');
_GVAdBreak = function(callback) {
if (typeof callback === 'function') setTimeout(callback, 10);
};
} else {
_GVAdBreak = val;
}
}
});
// Also trap parent.GVAdBreak if the game runs inside an iframe (common on GameVui)
try {
if (window.parent && window.parent !== window) {
let _parentGVAdBreak = window.parent.GVAdBreak;
Object.defineProperty(window.parent, 'GVAdBreak', {
configurable: true,
enumerable: true,
get() { return _parentGVAdBreak; },
set(val) {
if (typeof val === 'function') {
log('parent.GVAdBreak assigned – replacing with stub');
_parentGVAdBreak = function(callback) {
if (typeof callback === 'function') setTimeout(callback, 10);
};
} else {
_parentGVAdBreak = val;
}
}
});
}
} catch (e) {
// cross‑origin iframe, ignore
}
log('ZeroAd v6 installed – ad SDK patching active');
})();