remove google tracking UWAA

remove google tracking

目前为 2017-07-12 提交的版本。查看 最新版本

// ==UserScript==
// @name           remove google tracking UWAA
// @namespace      jp.sceneq.rgtuwaaa
// @description    remove google tracking
// @version        0.6
// @include        https://www.google.*/*
// @grant          none
// @run-at         document-start
// ==/UserScript==

'use strict';

// jump
if(location.pathname === '/' && location.search !== ''){
	// localStorage.clear();
	location.search = '';
}

const yesman = function(){return true};
const tired = function(){};

// matching tracking paramaters
const badParametersNames = [
	'biw'
	,'bih'
	,'ei'
	,'sa'
	,'ved'
	,'source'
	,'prmd'
	,'bvm'
	,'bav'
	,'psi'
	,'stick'
	,'dq'
	,'ech'

	// image search
	,'scroll'
	,'vet'
	,'yv'
	,'ijn'
	,'iact'
	,'forward'
	,'ndsp'
	,'csi'
	,'tbnid'
	,'docid'
	//,'imgdii'  // related images

	// search form
	,'pbx'
	,'dpr'
	,'pf'
	,'gs_rn'
	,'gs_mss'
	,'pq'
	,'cp'
	,'oq'
	,'sclient'
	,'gs_l'
	,'aqs'
	//,'gs_ri'   // suggestions
	//,'gs_id'   // suggestions
	//,'xhr'     // suggestions at image search
	//,'tch'     // js flag?

	// mobile
	,'gs_gbg'
	,'gs_rn'
	,'cp'
];
const badAttrNamesObj = {
	default: ['onmousedown', 'jsaction', 'ping', 'oncontextmenu'],
	search: ['onmousedown', 'jsaction', 'ping', 'oncontextmenu'],
	vid: ['onmousedown'],
	isch: [],
};

// From the nodes selected here, delete parameters specified by badParametersNames
const dirtyLinkSelectors = [
	// menu
	'a.q.qs',

	// doodle
	'a.doodle',
];

const badPaths = ["imgevent"];

/* Compile */
// The first paramater is probably 'q' so '?' does not consider
const regBadParameters = new RegExp(
	'&(?:' + badParametersNames.join('|') + ')=.*?(?=(&|$))'
	, 'g');
const regBadPaths = new RegExp(
	'^\/(?:' + badPaths.join('|') + ')'
);
const dirtyLinkSelector = dirtyLinkSelectors.map(s=>s+":not([href=''])").join(',');

/*
 * Functions
 */
/* Return parameter value */
function extractDirectLink(str, param){
	//(?<=q=)(.*)(?=&)/
	const res = new RegExp(`[?&]${param}(=([^&#]*))`).exec(str);
	if(!res || !res[2]) return '';
	return decodeURIComponent(res[2]);
}

/* Return the current Google search mode */
function getParam(parameter, name){
	var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(parameter);
	if (results === null){
		return null;
	}
	else{
		return results.pop() || 0;
	}
}

/* return search mode */
function getMode(){
	const parameter = location.search + location.hash;
	return getParam(parameter, 'tbm') || "search";
}

function sleep(ms) {
	return new Promise(resolve => setTimeout(resolve, ms));
}

/* Return Promise when declared the variable name specified by argument */
async function onDeclare(obj, propertyStr, interval=80) {
	return new Promise(async function(resolve, reject){
		const propertyNames = propertyStr.split(".");
		let currObj = obj;
		for(const propertyName of propertyNames){
			while(!(propertyName in currObj) || currObj[propertyName] === null){
				await sleep(interval);
			}
			currObj = currObj[propertyName];
		}
		resolve(currObj);
	});
}

function removeDOM(node){
	node.parentNode.removeChild(node);
}

function rewriteProperties(prop){
	prop.forEach((table) => {
		//const targetObject = typeof table[0] === 'function' ? table[0]() : table[0];
		Object.defineProperty(table[0] || {}, table[1], {
			value: table[2],
			writable: false,
		});
	});
}

function load(){
	console.time("LOAD");

	/* Overwrite disturbing  functions */
	rewriteProperties([
		[window, "rwt", yesman],
		[window.gbar_, 'Rm', yesman],
	]);

	// Do not send gen_204 flag
	for(const node of document.querySelectorAll(".csi")){
		node.parentNode.removeChild(node);
	}

	/*
	 * Variables
	 */
	// Whether to use AJAX
	const legacy = document.getElementById("cst") === null;

	/* Nodes */
	const nodeMain = window.main;
	const nodeCnt = window.cnt;
	const root = (()=>{
		if(legacy){
			return nodeCnt || nodeMain || window.document;
		} else {
			return nodeMain
		}
	})();

	// Flag indicating whether the hard tab is loaded on 'DOMContentLoaded'
	const lazy_hdtb = !legacy || root === nodeCnt;

	// Define selector function
	const $ = root.querySelector.bind(root);
	const $$ = (sel) => Array.prototype.slice.call(root.querySelectorAll.call(root, [sel]));

	// Selector pointing to anchors to purify
	const dirtySelector = (()=>{
		if(root === window.document){
			return "body a";
		} else if(legacy){
			return `#${root.id} a`;
		} else {
			return "#rcnt a";
		}
	})();

	/*
	 * Functions
	 */
	function removeTracking(){
		console.time("removeTracking");
		const mode = getMode();
		const badAttrNames = badAttrNamesObj[mode] ?
			badAttrNamesObj[mode] : badAttrNamesObj["default"];
		//const directLinkParamName = mode === 'isch' ? "url" : 'q';
		const directLinkParamName = 'q';

		// search result
		for(const searchResult of $$(dirtySelector)){
			// remove attributes
			badAttrNames.map((s)=>{ searchResult.removeAttribute(s); });

			// hide referrer
			searchResult.rel = 'noreferrer';

			// remove google redirect link(legacy)
			if (searchResult.hasAttribute('href') && searchResult.getAttribute('href').startsWith('/url?')){
				searchResult.href = extractDirectLink(searchResult.href, directLinkParamName);
			}
			searchResult.href = searchResult.href.replace(regBadParameters, '');
		}
		for(const dirtyLink of document.querySelectorAll(dirtyLinkSelector)){
			dirtyLink.href = dirtyLink.href.replace(regBadParameters, '');
		}

		switch(mode){
			case "shop":
				// Overwrite links(desktop version only)
				//Object.values(google.pmc.smpo.r).map(s=>{return {title:s[14][0],link:s[28][8]}})
				if(legacy) break;
				onDeclare(google, "pmc.spop.r").then((shopObj) => {
					const shopElements = $$(".pstl");
					const shopLinks = Object.values(shopObj).map(a=>a[34][6]);

					if(shopElements.length !== shopLinks.length) {
						console.warn("length does not match", shopElements.length, shopLinks.length);
						return;
					}

					const zip = rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
					for(const detail of zip([shopElements, shopLinks])){
						detail[0].href = detail[1];
					}
					console.log("Links Rewrited");
				});
				break;
			default:
				break;
		}
		console.timeEnd("removeTracking");
	}

	function startObserve(targetElement, op, func, conf={childList:true}){
		//console.log("Operation", op , "Register To", targetElement)
		new MutationObserver((mutations, observer) => {
			let nodes = Array.prototype.concat.apply([],
				mutations.map(s => Array.prototype.slice.call(s.addedNodes))
			).filter(n => n.nodeName !== '#comment');

			//console.log("Nodes Captured By", op, nodes);

			switch(op){
				case "FORMLOADED":
					nodes = nodes.filter(n => n.name === "gs_l");
					break;
				case "IMAGELOADED":
					nodes = nodes.filter(n => n.classList.contains("irc_bg"));
					break;
				case "HDTBLOADED":
					nodes = nodes.filter(n => n.className === "hdtb-mn-cont");
					break;
				case "HDTBUPDATE":
					nodes = nodes.filter(n => n.className === "hdtb-mn-cont");
					break;
				case "HDTBCHANGE":
					nodes = nodes.filter(n => n.id === "cnt");
					break;
				case "PAGECHANGE":
					nodes = nodes.filter(n => n.dataset && n.dataset.ved !== undefined);
					break;
				default:
					break;
			}

			if(nodes.length >= 1){
				//console.log("Operation", op , "Fired", nodes[0])
				func();
				if(["HDTBLOADED", "IMAGELOADED", "FORMLOADED"].includes(op)){
					observer.disconnect();
				}
			}
		}).observe(targetElement, conf);
	}

	function pageInit(){
		removeTracking();
		startObserve($("#search"), "PAGECHANGE", removeTracking);
	}

	const initMode = getMode();
	const confDeepObserve = {childList:true, subtree:true};

	// Wait for .hdtb-mn-cont appears in the first page access
	if(lazy_hdtb && !legacy){
		startObserve(root, "HDTBLOADED", ()=>{
			switch(initMode){
				case "isch": // Image Search
					removeTracking();
					startObserve($("#isr_mc"), "IMAGELOADED", ()=>{
						$$(".irc_tas, .irc_mil, irc_hol, .irc_but[jsaction*='mousedown']").forEach((e)=>{
							e.__jsaction = null;
							e.removeAttribute("jsaction");
						});
					});
					startObserve($("#top_nav"), "HDTBUPDATE", removeTracking, confDeepObserve);
					break;
				default:
					pageInit();
					// Wait for #cnt inserted. In HDTB switching, since .hdtb-mn-cont does not appear
					startObserve(root, "HDTBCHANGE", pageInit);
					break;
			}
		}, confDeepObserve);
	}

	if(legacy){
		removeTracking();

		startObserve(document.querySelector("form"), "FORMLOADED", ()=>{
			document.querySelectorAll("form input:not([name='q']):not([name='hl'])")
				.forEach(s=>removeDOM(s));
		});

		console.warn("legacy mode");
		console.timeEnd("LOAD");
		return;
	}

	console.timeEnd("LOAD");
}

(function init(){
	console.time("init");

	onDeclare(window, "google", 20).then(()=>{
		rewriteProperties([
			[google, 'log', yesman],
			[google, 'rll', yesman],
			[google, 'logUrl', tired],
			[google, 'getEI', yesman],
			[google, 'getLEI', yesman],
			[google, 'ctpacw', yesman],
			[google, 'csiReport', yesman],
			[google, 'report', yesman],
			[google, 'aft', yesman],
			[google, 'kEI', '0'],
		]);
	});

	// Reject Request by img tag
	const regBadImageSrc = /\/(?:gen(?:erate)?|client)_204/;
	Object.defineProperty(
		window.Image.prototype,
		"src",
		{
			set: function(url){
				if(!regBadImageSrc.test(url)){
					this.setAttribute("src", url);
				}
			},
		},
	);

	// Reject unknown parameters by script tag
	Object.defineProperty(
		window.HTMLScriptElement.prototype,
		"src",
		{
			set: function(url){
				this.setAttribute("src", url.replace(regBadParameters,''));
			},
		},
	);

	// hook XHR
	const origOpen = XMLHttpRequest.prototype.open;
	window.XMLHttpRequest.prototype.open = function(act, path) {
		if(regBadPaths.test(path)){
			return;
		}
		// take over the parameters ex:num=20
		// path += location.search.replace(/./, '');
		origOpen.apply(this, [act, path.replace(regBadParameters, '')]);
	};

	// do not send referrer
	const noreferrerMeta = document.createElement("meta");
	noreferrerMeta.setAttribute("name", "referrer");
	noreferrerMeta.setAttribute("content", "no-referrer");
	document.querySelector("head").appendChild(noreferrerMeta);

	console.timeEnd("init");
})();

window.addEventListener('DOMContentLoaded', load);

// for older browser
if(document.getElementById("universal") !== null){
	load();
}

QingJ © 2025

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