Google Infinite scroll and Favicons

-

As of 2022-05-30. See the latest version.

// ==UserScript==
// @name:ko           구글 무한스크롤과 파비콘
// @name              Google Infinite scroll and Favicons
// @name:ru           Google Бесконечный свиток и фавиконы
// @name:ja           Google無限スクロールおよびFavicons
// @name:zh-TW        Google无限滚动和Favicons
// @name:zh-CN        Google無限滾動和Favicons

// @description:ko    -
// @description       -
// @description:ru    -
// @description:ja    -
// @description:zh-TW -
// @description:zh-CN -

// @namespace         https://ndaesik.tistory.com/
// @version           2022.05.30.19.13
// @author            ndaesik
// @icon              https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://www.google.com
// @match             *://www.google.com/search*
// ==/UserScript==

let target = document.querySelector("[aria-current]")
  , checkerAllResultsPage = target !== null && target.previousSibling == null

if (checkerAllResultsPage) {
    // remove navigation below of a suggestion box
    document.querySelector('#botstuff [role="navigation"]').style.cssText = 'visibility: hidden; height: 0;';

    // create favicons
    function createFavicons(target) {
        for (let i = 0; i < target.querySelectorAll('cite').length; ++i) {
            let lnk = target.querySelector('#center_col>[role="main"]').querySelectorAll('cite')[i]
            , txt = lnk.textContent
            , url = txt.match(/\./g) ? (txt.match(/\/\//g) ? txt.match(/(?<=\/\/)[^\s]*/g) : txt.match(/^[^\s]*/g)) : null
            , fav = url ? '/s2/favicons?domain=' + url : '';
            if (url) {
                let img = target.createElement('div');
                img.style.cssText = `background-image:url("${fav}"); width:16px; height:16px; display:inline-block; margin-right:6px`;
                lnk.prepend(img)
                lnk.style.cssText = 'display:inline-block'
            }
        }
    };
    createFavicons(document);

    // load pages when it's bottom + create favicons
    let pageNumber = 0
    , loadNewResults = _=> {
        let nextURL = new URL((document.querySelector('[role="navigation"]>[role="presentation"] a:first-child').href).replace(/(?<=start=)(.*?)(?=\&)/g,pageNumber * 10));
        fetch( nextURL.href )
            .then(response => response.text())
            .then(text => {
            let newDocument = (new DOMParser()).parseFromString( text, 'text/html'),
                newResults = newDocument.documentElement.querySelector('#center_col > [role="main"]')
            createFavicons(newDocument);

            // remove junks, '.g' are only good
            for (let i = 0; newResults.querySelectorAll('[data-async-context] > div:not(.g)').length; ++i) {
                newResults.querySelectorAll('[data-async-context] > div:not(.g)')[i].remove()
            }

            // put results to bottom of main area
            if ( newDocument.querySelector('.g') !== null) {
                document.createElement('div').appendChild(newResults)
                document.querySelector('#center_col > [role="main"]').parentElement.appendChild(newResults)
            }
        })
    };

    // run, when it's bottom. '-2' for make it less strictly
    document.addEventListener('scroll', () => {
        if (window.innerHeight + window.pageYOffset >= document.body.offsetHeight - 2) {
            pageNumber = pageNumber + 1
            loadNewResults()
        }
    });
}