// ==UserScript==
// @name remove google tracking UWAA
// @namespace jp.sceneq.rgtuwaaa
// @description remove google tracking
// @version 0.4
// @include https://www.google.*/*
// @grant none
// @run-at document-start
// ==/UserScript==
'use strict';
// jump
if(location.pathname === '/' && location.search !== ''){
// localStorage.clear();
location.search = '';
}
// matching tracking paramaters
const badParametersNames = [
'biw'
,'bih'
,'ei'
,'sa'
,'ved'
,'source'
,'prmd'
,'bvm'
,'bav'
,'psi'
,'stick'
,'dq'
//search
,'scroll'
,'vet'
,'yv'
,'ijn'
,'iact'
,'forward'
,'ndsp'
];
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',
];
/* Compile */
// The first paramater is probably 'q' so '?' does not consider
const regBadParameters = new RegExp(
'&(?:' + badParametersNames.join('|') + ')=.*?(?=(&|$))'
, 'g');
const dirtyLinkSelector = dirtyLinkSelectors.map(s=>s+":not([href=''])").join(',');
/*
* Functions
*/
/* Return 'q' parameter value */
function extractDirectLink(str){
//(?<=q=)(.*)(?=&)/
const res = /[?&]q(=([^&#]*))/.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 waitForDeclare(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 rewriteFunctions(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 */
const yesman = function(){return true};
const tired = function(){};
rewriteFunctions([
[window, "rwt", yesman],
[window.gbar_, 'Rm', yesman],
[google, 'rll', yesman],
[google, 'log', yesman],
[google, 'logUrl', tired],
[google, 'getEI', yesman],
[google, 'getLEI', yesman],
[google, 'ctpacw', yesman],
[google, 'csiReport', yesman],
[google, 'report', yesman],
[google, 'aft', 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 || nodeCnt || window.document;
}
})();
// 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 "#cnt a";
} else {
return "#rcnt a";
}
})();
/*
* Functions
*/
function removeTracking(nodes=[]){
console.time("removeTracking");
const mode = getMode();
const badAttrNames = badAttrNamesObj[mode] ?
badAttrNamesObj[mode] : badAttrNamesObj["default"];
// search result
for(const dirtyAnchor of $$(dirtySelector)){
// remove attributes
badAttrNames.map((s)=>{ dirtyAnchor.removeAttribute(s); });
// hide referrer
dirtyAnchor.rel = 'noreferrer';
// remove google redirect link(legacy)
if (dirtyAnchor.hasAttribute('href') && dirtyAnchor.getAttribute('href').startsWith('/url?')){
dirtyAnchor.href = extractDirectLink(dirtyAnchor.href);
}
dirtyAnchor.href = dirtyAnchor.href.replace(regBadParameters, '');
}
for(const dirtyLink of $$(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;
waitForDeclare(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 === 'DIV');
//console.log("Nodes Captured By", op, nodes);
switch(op){
case "IMAGE":
// Exclude DOM inserted at click
nodes = nodes.filter(n => n.id !== "irc_pbg");
break;
case "HDTBLOADED":
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"].includes(op)){
observer.disconnect();
}
}
}).observe(targetElement, conf);
}
function pageInit(){
removeTracking();
startObserve($("#search"), "PAGECHANGE", removeTracking);
}
if(legacy){
removeTracking();
console.timeEnd("LOAD");
console.warn("legacy mode");
return;
}
const initMode = getMode();
if(initMode === "isch"){ // image search
removeTracking();
startObserve($("#rg_s"), "IMAGE", removeTracking);
return;
}
// Wait for .hdtb-mn-cont appears in the first page access
startObserve(nodeMain, "HDTBLOADED", ()=>{
pageInit();
// Wait for #cnt inserted. In HDTB switching, since .hdtb-mn-cont does not appear
startObserve(nodeMain, "HDTBCHANGE", pageInit);
}, {childList:true, subtree:true});
console.timeEnd("LOAD");
}
(function init(){
// hook XHR
const origOpen = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function(act, path) {
// 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);
})();
window.addEventListener('DOMContentLoaded', load);
// for older browser
if(document.getElementById("universal") !== null){
load();
}