Greasy Fork is available in English.

Google搜尋顯示桌面版網站

把 google 搜尋結果的行動裝置版網站取代為桌面版網站

// ==UserScript==
// @name               Google搜尋顯示桌面版網站
// @name:en            Desktop Website for Google Search
// @name:zh-TW         Google搜尋顯示桌面版網站
// @namespace          https://github.com/rod24574575
// @description        把 google 搜尋結果的行動裝置版網站取代為桌面版網站
// @description:en     Replace the google search result from mobile to desktop website.
// @description:zh-TW  把 google 搜尋結果的行動裝置版網站取代為桌面版網站
// @version            1.0.2
// @license            MIT
// @author             rod24574575
// @homepage           https://github.com/rod24574575/monorepo
// @homepageURL        https://github.com/rod24574575/monorepo
// @supportURL         https://github.com/rod24574575/monorepo/issues
// @match              *://*.google.com/search*
// @match              *://*.google.ad/search*
// @match              *://*.google.ae/search*
// @match              *://*.google.com.af/search*
// @match              *://*.google.com.ag/search*
// @match              *://*.google.al/search*
// @match              *://*.google.am/search*
// @match              *://*.google.co.ao/search*
// @match              *://*.google.com.ar/search*
// @match              *://*.google.as/search*
// @match              *://*.google.at/search*
// @match              *://*.google.com.au/search*
// @match              *://*.google.az/search*
// @match              *://*.google.ba/search*
// @match              *://*.google.com.bd/search*
// @match              *://*.google.be/search*
// @match              *://*.google.bf/search*
// @match              *://*.google.bg/search*
// @match              *://*.google.com.bh/search*
// @match              *://*.google.bi/search*
// @match              *://*.google.bj/search*
// @match              *://*.google.com.bn/search*
// @match              *://*.google.com.bo/search*
// @match              *://*.google.com.br/search*
// @match              *://*.google.bs/search*
// @match              *://*.google.bt/search*
// @match              *://*.google.co.bw/search*
// @match              *://*.google.by/search*
// @match              *://*.google.com.bz/search*
// @match              *://*.google.ca/search*
// @match              *://*.google.cd/search*
// @match              *://*.google.cf/search*
// @match              *://*.google.cg/search*
// @match              *://*.google.ch/search*
// @match              *://*.google.ci/search*
// @match              *://*.google.co.ck/search*
// @match              *://*.google.cl/search*
// @match              *://*.google.cm/search*
// @match              *://*.google.cn/search*
// @match              *://*.google.com.co/search*
// @match              *://*.google.co.cr/search*
// @match              *://*.google.com.cu/search*
// @match              *://*.google.cv/search*
// @match              *://*.google.com.cy/search*
// @match              *://*.google.cz/search*
// @match              *://*.google.de/search*
// @match              *://*.google.dj/search*
// @match              *://*.google.dk/search*
// @match              *://*.google.dm/search*
// @match              *://*.google.com.do/search*
// @match              *://*.google.dz/search*
// @match              *://*.google.com.ec/search*
// @match              *://*.google.ee/search*
// @match              *://*.google.com.eg/search*
// @match              *://*.google.es/search*
// @match              *://*.google.com.et/search*
// @match              *://*.google.fi/search*
// @match              *://*.google.com.fj/search*
// @match              *://*.google.fm/search*
// @match              *://*.google.fr/search*
// @match              *://*.google.ga/search*
// @match              *://*.google.ge/search*
// @match              *://*.google.gg/search*
// @match              *://*.google.com.gh/search*
// @match              *://*.google.com.gi/search*
// @match              *://*.google.gl/search*
// @match              *://*.google.gm/search*
// @match              *://*.google.gr/search*
// @match              *://*.google.com.gt/search*
// @match              *://*.google.gy/search*
// @match              *://*.google.com.hk/search*
// @match              *://*.google.hn/search*
// @match              *://*.google.hr/search*
// @match              *://*.google.ht/search*
// @match              *://*.google.hu/search*
// @match              *://*.google.co.id/search*
// @match              *://*.google.ie/search*
// @match              *://*.google.co.il/search*
// @match              *://*.google.im/search*
// @match              *://*.google.co.in/search*
// @match              *://*.google.iq/search*
// @match              *://*.google.is/search*
// @match              *://*.google.it/search*
// @match              *://*.google.je/search*
// @match              *://*.google.com.jm/search*
// @match              *://*.google.jo/search*
// @match              *://*.google.co.jp/search*
// @match              *://*.google.co.ke/search*
// @match              *://*.google.com.kh/search*
// @match              *://*.google.ki/search*
// @match              *://*.google.kg/search*
// @match              *://*.google.co.kr/search*
// @match              *://*.google.com.kw/search*
// @match              *://*.google.kz/search*
// @match              *://*.google.la/search*
// @match              *://*.google.com.lb/search*
// @match              *://*.google.li/search*
// @match              *://*.google.lk/search*
// @match              *://*.google.co.ls/search*
// @match              *://*.google.lt/search*
// @match              *://*.google.lu/search*
// @match              *://*.google.lv/search*
// @match              *://*.google.com.ly/search*
// @match              *://*.google.co.ma/search*
// @match              *://*.google.md/search*
// @match              *://*.google.me/search*
// @match              *://*.google.mg/search*
// @match              *://*.google.mk/search*
// @match              *://*.google.ml/search*
// @match              *://*.google.com.mm/search*
// @match              *://*.google.mn/search*
// @match              *://*.google.com.mt/search*
// @match              *://*.google.mu/search*
// @match              *://*.google.mv/search*
// @match              *://*.google.mw/search*
// @match              *://*.google.com.mx/search*
// @match              *://*.google.com.my/search*
// @match              *://*.google.co.mz/search*
// @match              *://*.google.com.na/search*
// @match              *://*.google.com.ng/search*
// @match              *://*.google.com.ni/search*
// @match              *://*.google.ne/search*
// @match              *://*.google.nl/search*
// @match              *://*.google.no/search*
// @match              *://*.google.com.np/search*
// @match              *://*.google.nr/search*
// @match              *://*.google.nu/search*
// @match              *://*.google.co.nz/search*
// @match              *://*.google.com.om/search*
// @match              *://*.google.com.pa/search*
// @match              *://*.google.com.pe/search*
// @match              *://*.google.com.pg/search*
// @match              *://*.google.com.ph/search*
// @match              *://*.google.com.pk/search*
// @match              *://*.google.pl/search*
// @match              *://*.google.pn/search*
// @match              *://*.google.com.pr/search*
// @match              *://*.google.ps/search*
// @match              *://*.google.pt/search*
// @match              *://*.google.com.py/search*
// @match              *://*.google.com.qa/search*
// @match              *://*.google.ro/search*
// @match              *://*.google.ru/search*
// @match              *://*.google.rw/search*
// @match              *://*.google.com.sa/search*
// @match              *://*.google.com.sb/search*
// @match              *://*.google.sc/search*
// @match              *://*.google.se/search*
// @match              *://*.google.com.sg/search*
// @match              *://*.google.sh/search*
// @match              *://*.google.si/search*
// @match              *://*.google.sk/search*
// @match              *://*.google.com.sl/search*
// @match              *://*.google.sn/search*
// @match              *://*.google.so/search*
// @match              *://*.google.sm/search*
// @match              *://*.google.sr/search*
// @match              *://*.google.st/search*
// @match              *://*.google.com.sv/search*
// @match              *://*.google.td/search*
// @match              *://*.google.tg/search*
// @match              *://*.google.co.th/search*
// @match              *://*.google.com.tj/search*
// @match              *://*.google.tl/search*
// @match              *://*.google.tm/search*
// @match              *://*.google.tn/search*
// @match              *://*.google.to/search*
// @match              *://*.google.com.tr/search*
// @match              *://*.google.tt/search*
// @match              *://*.google.com.tw/search*
// @match              *://*.google.co.tz/search*
// @match              *://*.google.com.ua/search*
// @match              *://*.google.co.ug/search*
// @match              *://*.google.co.uk/search*
// @match              *://*.google.com.uy/search*
// @match              *://*.google.co.uz/search*
// @match              *://*.google.com.vc/search*
// @match              *://*.google.co.ve/search*
// @match              *://*.google.co.vi/search*
// @match              *://*.google.com.vn/search*
// @match              *://*.google.vu/search*
// @match              *://*.google.ws/search*
// @match              *://*.google.rs/search*
// @match              *://*.google.co.za/search*
// @match              *://*.google.co.zm/search*
// @match              *://*.google.co.zw/search*
// @match              *://*.google.cat/search*
// @run-at             document-idle
// ==/UserScript==

// The google domains are from the following link:
// https://www.google.com/supported_domains

// @ts-check
'use strict';

(function() {
  /**
   * @typedef {(url: string) => string | null} UrlTransformer
   */

  /**
   * @typedef {UrlTransformer | [searcher: RegExp, replacer: string | ((url: string, matches: RegExpExecArray) => string)]} UrlTransformerLike
   */

  /**
   * @param {UrlTransformerLike} transformerLike
   * @returns {UrlTransformer}
   */
  function ensureUrlTransformer(transformerLike) {
    if (typeof transformerLike === 'function') {
      return transformerLike;
    }

    let [searcher, replacer] = transformerLike;
    if (typeof replacer === 'string') {
      const replacementString = replacer;
      replacer = (url, matches) => {
        return url.slice(0, matches.index) + replacementString + url.slice(matches.index + matches[0].length);
      };
    }
    return (url) => {
      const matches = searcher.exec(url);
      if (!matches) {
        return null;
      }
      return replacer(url, matches);
    };
  }

  /** @type {Array<[urlTransformerLike: UrlTransformerLike, hostTransformerLike?: UrlTransformerLike]>} */
  const patterns = [
    [[/\.m\.wikipedia\.org/, '.wikipedia.org']],
    [
      [/m\d*\.momoshop\.com\.tw\/(main|goods|search|category)\.momo\b/, (url, matches) => {
        const target = matches.at(1);

        const before = url.slice(0, matches.index);
        let replacement = 'www.momoshop.com.tw/';
        let after = url.slice(matches.index + matches[0].length);

        if (target) {
          switch (target) {
            case 'main':
              replacement += 'main/Main.jsp';
              break;
            case 'goods':
              replacement += 'goods/GoodsDetail.jsp';
              break;
            case 'search':
              replacement += 'search/searchShop.jsp';
              after = after.replace('searchKeyword=', 'keyword=');
              break;
            case 'category':
              replacement += 'category/LgrpCategory.jsp';
              after = after.replace('cn=', 'l_code=');
              break;
            default:
              break;
          }
        }

        return before + replacement + after;
      }],
      [/m\d*\.momoshop\.com\.tw/, 'www.momoshop.com.tw'],
    ],
  ];

  /** @type {ReadonlyArray<[urlTransformer: UrlTransformer, hostTransformer: UrlTransformer]>} */
  const transformers = patterns.map(([urlTransformerLike, hostTransformerLike]) => {
    const urlTransformer = ensureUrlTransformer(urlTransformerLike);
    const hostTransformer = hostTransformerLike ? ensureUrlTransformer(hostTransformerLike) : urlTransformer;
    return [urlTransformer, hostTransformer];
  });

  /** @type {WeakSet<Element>} */
  const cacheSet = new WeakSet();

  function run() {
    for (const anchorElement of /** @type {NodeListOf<HTMLAnchorElement>} */ (document.querySelectorAll('a[href][data-ved]:has(> br):has(> h3):has(> div.notranslate)'))) {
      if (cacheSet.has(anchorElement)) {
        continue;
      }
      cacheSet.add(anchorElement);

      for (const [urlTransformer, hostTransformer] of transformers) {
        const href = urlTransformer(anchorElement.href);
        if (href == null) {
          continue;
        }

        anchorElement.href = href;

        // Only for chrome.
        const pingAttribute = anchorElement.getAttribute('ping');
        if (pingAttribute) {
          const result = urlTransformer(decodeURIComponent(pingAttribute));
          if (result != null) {
            anchorElement.setAttribute('ping', encodeURIComponent(result));
          }
        }

        const anchorCiteChild = anchorElement.querySelector('cite')?.firstChild;
        if (anchorCiteChild && anchorCiteChild.nodeType === anchorCiteChild.TEXT_NODE) {
          const citeText = /** @type {Text} */ (anchorCiteChild);
          const result = hostTransformer(citeText.data);
          if (result != null) {
            citeText.data = result;
          }
        }

        const infoCiteChild = anchorElement.parentElement?.nextElementSibling?.querySelector('cite')?.firstChild;
        if (infoCiteChild && infoCiteChild.nodeType === infoCiteChild.TEXT_NODE) {
          const citeText = /** @type {Text} */ (infoCiteChild);
          const result = hostTransformer(citeText.data);
          if (result != null) {
            citeText.data = result;
          }
        }

        // Bypass google's link redirection warning.
        anchorElement.removeAttribute('data-jsarwt');
        break;
      }
    }
  }

  function main() {
    const mutationObserver = new MutationObserver(run);
    mutationObserver.observe(document.body, { childList: true, subtree: true });
    run();
  }

  main();
})();