您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
remove google tracking
当前为
- // ==UserScript==
- // @namespace jp.sceneq.rgtuwaaa
- // @name remove google tracking UWAA
- // @description remove google tracking
- // @homepageURL https://github.com/sceneq/RemoveGoogleTracking
- // @version 0.20
- // @include https://www.google.*/*
- // @grant none
- // @run-at document-body
- // @author sceneq
- // @license MIT
- // ==/UserScript==
- const yes = () => true;
- const doNothing = () => {};
- const $ = (s, n = document) => n.querySelector(s);
- const $$ = (s, n = document) => [...n.querySelectorAll(s)];
- const sleep = millis => new Promise(resolve => setTimeout(resolve, millis));
- const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]));
- const rewriteProperties = props => {
- for (const p of props) {
- Object.defineProperty(p[0] || {}, p[1], {
- value: p[2],
- writable: false,
- });
- }
- };
- const waitUntilDeclare = ({ obj, property, interval }) => {
- console.debug('waitUntilDeclare', obj.toString(), property);
- return new Promise(async (resolve, reject) => {
- const propertyNames = property.split('.');
- let currObj = obj;
- for (const propertyName of propertyNames) {
- while (!(propertyName in currObj) || currObj[propertyName] === null) {
- await sleep(interval);
- }
- currObj = currObj[propertyName];
- }
- console.debug('waitUntilDeclare', obj.toString(), property, 'Done');
- resolve(currObj);
- });
- };
- const untrackBuilder = arg => {
- const r = arg.badParamsRegex;
- return a => {
- const href = a.getAttribute('href');
- if(href === null) return;
- if (href.startsWith('/url?')) {
- a.href = new URLSearchParams(href.slice(5)).get('q');
- } else {
- a.removeAttribute('ping');
- a.href = a.href.replace(r, '');
- }
- };
- };
- const Types = {
- search: Symbol('search'),
- isch: Symbol('image'),
- shop: Symbol('shop'),
- nws: Symbol('news'),
- vid: Symbol('video'),
- bks: Symbol('book'),
- maps: Symbol('maps'),
- fin: Symbol('finance'),
- toppage: Symbol('toppage'),
- // flights: Symbol('flights'),
- };
- const tbmToType = tbm => {
- if (tbm === null) {
- return Types.search;
- }
- const t = {
- isch: Types.isch,
- shop: Types.shop,
- nws: Types.nws,
- vid: Types.vid,
- bks: Types.bks,
- fin: Types.fin,
- }[tbm];
- if (t === undefined) {
- return null;
- } else {
- return t;
- }
- };
- const BadParamsBase = [
- 'biw', // offsetWidth
- 'bih', // offsetHeight
- 'ei',
- 'sa',
- 'ved',
- 'source',
- 'prds',
- 'bvm',
- 'bav',
- 'psi',
- 'stick',
- 'dq',
- 'ech',
- 'gs_gbg',
- 'gs_rn',
- 'cp',
- 'ictx',
- 'cshid',
- 'gs_lcp',
- ];
- const BadParams = (() => {
- const o = {};
- o[Types.search] = [
- 'pbx',
- 'dpr',
- 'pf',
- 'gs_rn',
- 'gs_mss',
- 'pq',
- 'cp',
- 'oq',
- 'sclient',
- 'gs_l',
- 'aqs',
- ];
- o[Types.isch] = [
- 'scroll',
- 'vet',
- 'yv',
- 'iact',
- 'forward',
- 'ndsp',
- 'csi',
- 'tbnid',
- 'sclient',
- 'oq',
- ];
- o[Types.shop] = ['oq'];
- o[Types.nws] = ['oq'];
- o[Types.vid] = ['oq'];
- o[Types.bks] = ['oq'];
- o[Types.fin] = ['oq'];
- o[Types.toppage] = ['oq', 'sclient', 'uact'];
- o[Types.maps] = ['psi'];
- return o;
- })();
- const searchFormUriuri = async arg => {
- let form = null;
- if (arg.pageType.mobileOld) {
- form = $('#sf');
- } else if (arg.pageType.ty === Types.isch) {
- form = await waitUntilDeclare({
- obj: window,
- property: 'sf',
- interval: 30,
- });
- } else {
- form = await waitUntilDeclare({
- obj: window,
- property: 'tsf',
- interval: 30,
- });
- }
- if (form === null) {
- console.warn('form === null');
- return;
- }
- for (const i of form) {
- if (i.tagName !== 'INPUT') continue;
- if (arg.badParams.includes(i.name)) {
- i.parentElement.removeChild(i);
- }
- }
- const orig = form.appendChild.bind(form);
- form.appendChild = e => {
- if (!arg.badParams.includes(e.name)) {
- orig(e);
- }
- };
- };
- const untrackAnchors = (untrack, arg) => {
- return waitUntilDeclare({
- obj: window,
- property: arg.pageType.mobile
- ? 'topstuff'
- : arg.pageType.mobileOld
- ? 'rmenu'
- : 'search',
- interval: 30,
- }).then(_ => {
- for (const a of $$('a')) {
- untrack(a);
- }
- });
- };
- const gcommon = async arg => {
- const untrack = untrackBuilder(arg);
- const p1 = waitUntilDeclare({
- obj: window,
- property: 'google',
- interval: 30,
- }).then(google => {
- rewriteProperties([
- [google, 'log', yes],
- [google, 'logUrl', doNothing],
- [google, 'getLEI', yes],
- [google, 'ctpacw', yes],
- [google, 'csiReport', yes],
- [google, 'report', yes],
- [google, 'aft', yes],
- //[google, 'kEI', '0'],
- //[google, 'getEI', yes], or ()=>"0"
- ]);
- });
- rewriteProperties([
- [window, 'rwt', doNothing],
- [window.gbar_, 'Rm', doNothing],
- ]);
- const p2 = untrackAnchors(untrack, arg);
- const p3 = searchFormUriuri(arg);
- await Promise.all([p1, p2, p3]);
- if (arg.pageType.mobile) {
- const sel =
- arg.pageType.ty === Types.search
- ? '#bres + h1 + div > div + div'
- : '#bres + div > div + div';
- new MutationObserver(mutations => {
- const nodes = [];
- for (const m of mutations) {
- nodes.push(...m.addedNodes);
- }
- for (const n of nodes) {
- new MutationObserver((_, obs) => {
- console.debug('untrack', n);
- for (const a of $$('a', n)) {
- untrack(a);
- }
- obs.disconnect();
- }).observe(n, { childList: true });
- }
- }).observe($(sel), {
- childList: true,
- });
- }
- };
- const fun = {};
- // TODO mobile, mobileOld
- fun[Types.toppage] = searchFormUriuri;
- fun[Types.search] = gcommon;
- fun[Types.vid] = gcommon;
- fun[Types.nws] = gcommon;
- fun[Types.bks] = gcommon;
- fun[Types.fin] = gcommon;
- fun[Types.isch] = async arg => {
- // TODO desktop, mobile, mobileOld
- const untrack = untrackBuilder(arg);
- const p1 = waitUntilDeclare({
- obj: window,
- property: 'islmp',
- interval: 30,
- }).then(() => {
- for (const a of $$('a')) {
- untrack(a);
- }
- });
- const p2 = searchFormUriuri(arg);
- await Promise.all([p1, p2]);
- };
- fun[Types.shop] = async arg => {
- // TODO mobile, mobileOld
- const untrack = untrackBuilder(arg);
- const p1 = waitUntilDeclare({
- obj: window,
- property: 'google.pmc.spop.r',
- interval: 30,
- }).then(shopObj => {
- // Rewrite to original link
- const tmp = $$("div[class$='__content'] a[jsaction='spop.c']");
- const [anchors, thumbs] = [0, 1].map(m =>
- tmp.filter((_, i) => i % 2 === m)
- );
- const shops = Object.values(shopObj);
- const links = shops.map(a => a[34][6]);
- if (anchors.length === links.length) {
- for (const [anchor, link, thumb, shop] of zip([
- anchors,
- links,
- thumbs,
- shops,
- ])) {
- anchors.href = thumb.href = link;
- shop[3][0][1] = link;
- shop[14][1] = link;
- shop[89][16] = link;
- shop[89][18][0] = link;
- shop[85][3] = link;
- }
- } else {
- console.warn('length does not match', anchors.length, links.length);
- }
- });
- const p2 = untrackAnchors(untrack, arg);
- const p3 = searchFormUriuri(arg);
- await Promise.all([p1, p2, p3]);
- };
- // TODO fun[Types.maps] = async arg => {}
- (async () => {
- 'use strict';
- console.debug('rgt: init');
- console.time('rgt');
- const ty = (() => {
- if (location.pathname.startsWith('/maps')) {
- return Types.maps;
- }
- if (location.pathname === '/' || location.pathname === '/webhp') {
- return Types.toppage;
- }
- const tbm = new URLSearchParams(location.search).get('tbm');
- if (location.pathname === '/search') {
- return tbmToType(tbm);
- }
- return null;
- })();
- if (ty === null) {
- console.debug('ty === null');
- return;
- }
- const badParams = (() => {
- return [...BadParamsBase, ...BadParams[ty]];
- })();
- const badParamsRegex = new RegExp(
- '&(?:' + badParams.join('|') + ')=.*?(?=(&|$))',
- 'g'
- );
- const badImageSrcRegex = /\/(?:(?:gen(?:erate)?|client|fp)_|log)204|(?:metric|csi)\.gstatic\.|(?:adservice)\.(google)/;
- Object.defineProperty(window.Image.prototype, 'src', {
- set: function(url) {
- if (!badImageSrcRegex.test(url)) {
- this.setAttribute('src', url);
- }
- },
- });
- Object.defineProperty(window.HTMLScriptElement.prototype, 'src', {
- set: function(url) {
- this.setAttribute('src', url.replace(badParamsRegex, ''));
- },
- });
- const badPaths = [
- 'imgevent',
- 'shopping\\/product\\/.*?\\/popout',
- 'async/ecr',
- 'async/bgasy',
- ];
- const regBadPaths = new RegExp('^/(?:' + badPaths.join('|') + ')');
- const origOpen = XMLHttpRequest.prototype.open;
- window.XMLHttpRequest.prototype.open = function(act, path) {
- if (path === undefined) return;
- if (path.startsWith('https://aa.google.com/')) return;
- if (path.startsWith('https://play.google.com/log')) return;
- if (path.startsWith('https://www.google.com/log')) return;
- if (regBadPaths.test(path)) return;
- origOpen.apply(this, [act, path.replace(badParamsRegex, '')]);
- };
- if ('navigator' in window) {
- const origSendBeacon = navigator.sendBeacon.bind(navigator);
- navigator.sendBeacon = (path, data) => {
- if (path.startsWith('https://play.google.com/log')) return;
- if (badImageSrcRegex.test(path)) return;
- origSendBeacon(path, data);
- };
- }
- if (ty in fun) {
- const mobileOld = $("html[itemtype]") === null; // &liteui=2
- const mobile = !mobileOld && $('meta[name=viewport]') !== null;
- const arg = {
- pageType: {
- ty,
- mobile,
- mobileOld,
- },
- badParams,
- badParamsRegex,
- };
- console.debug('arg', arg);
- await fun[ty](arg);
- } else {
- console.warn(`key not found in fun: ${ty.toString()}`);
- }
- console.timeEnd('rgt');
- })();