Super google

Open google images in page instead of new tab

// ==UserScript==
// @name         Super google
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Open google images in page instead of new tab
// @author       Faris Hijazi
// @include      https://www.google.*
// @include      https://encrypted.google.com*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @require      http://code.jquery.com/jquery-latest.js
// @require      https://gf.qytechs.cn/scripts/38996-faris-handy-webdev-javascript-functions/code/Faris%20Handy%20Webdev%20JavaScript%20functions.user.js
// @run-at       document-end
// ==/UserScript==
// @require      https://github.com/buzamahmooza/Helpful-Web-Userscripts/raw/master/Handy%20AF%20functions%20Faris.user.js



// noinspection ES6ConvertVarToLetConst
var debug;
if (typeof debug === 'undefined') {
    debug = false;
}
if (typeof log === 'undefined') {
    log = function (msg) {
        if (debug) console.log('Log:', msg);
    };
}

const gImgSearchUrl = "https://encrypted.google.com/search?&hl=en&tbm=isch&q=";
const AUTO_SAVE_UBL_SITES = false;
const REPLACE_IMG_DATA = false;

if (typeof GM === 'undefined') // PRE GM4
{
    GM = {};
    // noinspection JSUnresolvedVariable
    GM.getValue = GM_getValue;
    // noinspection JSUnresolvedVariable
    GM.setValue = GM_setValue;
}

let storedSuccessfulUrlsSet = GM_getValue('unblocked sites of og images', new Set(['forumophilia.com']));
let ublSitesMap = GM_getValue('ublSitesMap', new Map([['forumphilia.com', '']]));
let successfulUrlsSet = new Set();

if (typeof unsafeWindow === "undefined") {
    unsafeWindow = window;
}

window.addEventListener("keydown", onkeydown, true);

// addToSet(storedSuccessfulUrlsSet, successfulUrlsSet);
storedSuccessfulUrlsSet.forEach(function (e, i, a) {
    successfulUrlsSet.add(e);
});
// log('Stored successfulUrlsSet:', storedSuccessfulUrlsSet);
// log('successfulUrlsSet:', successfulUrlsSet);

if (AUTO_SAVE_UBL_SITES) setInterval(storeSuccessfulUrlsSet, 5000);

function updateSuccessfulUrlsSet() {
    qa('.display-original-image').forEach(function (elt, index, array) {
        let siteUrl = "" + getHostname(getGimgRUrl(elt));
        if (/google\.com/.test(siteUrl)) siteUrl = getHostname(elt.getAttribute('rg_meta_ru'));
        if (/tumblr\.com/.test(siteUrl)) siteUrl = siteUrl.replace(/^\d*?\./);
        successfulUrlsSet.add(siteUrl);
        console.log('adding ubl site:', siteUrl);
    });
    console.log('in updateSuccessfulUrlsSet:', Array.from(successfulUrlsSet));
    return successfulUrlsSet; // returning just cuz it could be handy
}

function storeSuccessfulUrlsSet() {
    updateSuccessfulUrlsSet();
    var merged = new Set();
    var stored = GM_getValue('unblocked sites of og images');
    addToSet(merged, successfulUrlsSet);
    addToSet(merged, stored);

    var diff = Array.from(successfulUrlsSet).filter(x => Array.from(stored).indexOf(x) < 0);
    console.log("Found unblocked site that isn't in the database:", diff);

    // successfulUrlsSet;
    // addToSet(successfulUrlsSet, storedSuccessfulUrlsSet);
    GM_setValue('unblocked sites of og images', Array.from(merged));
    console.log('stored set:', GM_getValue('unblocked sites of og images'));
    // console.log('merged successfulUrlsSet:', Array.from(merged));
}

function observeDocument(callback) {
    callback(document.body);
    new MutationObserver(function (mutations) {
        for (let i = 0; i < mutations.length; i++) {
            if (!mutations[i].addedNodes.length)
                continue;
            callback(mutations[i].target);
        }
    }).observe(document.body, {
        childList: true, subtree: true,
        attributes: false, characterData: false
    });
}

function observePanel(callback) {
    new MutationObserver(function (mutations) {
        for (let i = 0; i < mutations.length; i++) {
            if (!mutations[i].addedNodes.length)
                continue;
            callback(mutations[i].target);
        }
    }).observe(ImagePanel.mainPanel, {
        childList: true, subtree: true,
        attributes: true, characterData: false
    });
}

for (let elt of Array.from(getAllImgEls)) {
    createAndAddAttribute(elt, 'download-name', getGimgDescription(elt));
}

let GIUtOST_MutOb = (window.MutationObserver) ? window.MutationObserver : window.WebKitMutationObserver;
if (REPLACE_IMG_DATA) {
    replaceImgData();
    observeDocument(replaceImgData);
}

if (GIUtOST_MutOb) {
    const GIUtOST_chgMon = new GIUtOST_MutOb(function (mutationSet) {
        mutationSet.forEach(function (mutation) {
            for (let i = 0; i < mutation.addedNodes.length; i++) { // noinspection EqualityComparisonWithCoercionJS
                if (mutation.addedNodes[i].nodeType == 1)
                    GIUtOST_checkNode(mutation.addedNodes[i]);
            }
        });
    }); // attach chgMon to document.body
    const opts = {childList: true, subtree: true};
    GIUtOST_chgMon.observe(document.body, opts);
}
GIUtOST_checkNode(document.elements);

function getAllImgEls() {
    return qa('img.rg_ic.rg_i');
}

/**abbreviation for querySelectorAll()*/
function qa(selector) {
    let x = document.querySelectorAll(selector);
    return x ? x : null;
}

function q(selector) {
    let x = document.querySelector(selector);
    return x ? x : null;
}

// Google images
function GIUtOST_checkNode(els) {
    clickLoadMoreImages(els);
    // showFullImageSiteURL(els);

    // var picBoxes = qa('[pic-not-found]'); if(picBoxes.length <= 0) return;
    // for(var i=0; i<picBoxes.length; i++) picBoxes[i] = picBoxes[i].parentNode.parentNode;
    // document.getElementsByClassName("rg_bx rg_di rg_el ivg-i");
    // if (picBoxes.length > 0) deleteElements(picBoxes);
}

function getImageBlocks() {
    return qa('.rg_bx');
}

function showFullImageSiteURL(els) {
    //siteAnchors
    try {
        if (els === null) return;
        var as = els.querySelectorAll('div.Q7Rsec');
        // console.log("as.length:" +as.length);
        for (var i = 0; i < as.length; i++) {
            var a = as[i];
            var getLocation = function (href) {
                var l = document.createElement("a");
                l.href = href;
                return l.hostname;
            };

            // if(a.classList.contains("ShowFullImageSiteURL")) break;
            // if(a.href.match("/null")) {console.log("match with null");break;}
            var host = getLocation(as[1].href);

            // siteSearchAnchor
            var ssa = document.createElement('a');
            ssa.href = (GoogleImagesSearchURL + "site:" + (host));
            // console.log("as["+i+"]: " +a.href);
            // console.log(i+"Ssa.href: "+  ssa.href);
            ssa.innerHTML = "site search[" + host + "]";
            let span = document.createElement('span');
            span.appendChild(ssa);
            a.parentNode.appendChild(span);
            a.classList.add("ShowFullImageSiteURL");
        }
    } catch (Exception) {
    }
}

// working :)
function clickLoadMoreImages(els) {
    var el = document.getElementById("smb");
    if (!el) return;
    el.click();
    // if(debug)console.log("Load more images");
}


//[Google.com images]
function getDataElement(imgN) {
    return imgN.parentNode.nextSibling;
}

function getDataText(imgN) {
    let data = "Not a main image, No data text available";
    try {
        data = getDataElement(imgN).innerHTML;
    } catch (exception) {
    }
    //	console.log('Data text:', data);
    return data;
}

function getGimgDescription(imgN) {
    let txt = getDataText(imgN);
    let title = extractFromText(txt, "ru");
    let desc = extractFromText(txt, "s");
    return title + "_" + desc;
    // desc.length > 1 ? desc : title; // choosing one of them (prioratizing the description over the title)
}

function getGimgTitle(imgN) {
    return extractImgData(imgN, 'pt');
}

function getGimgRUrl(imgN) {
    return extractImgData(imgN, 'ru');
}

function getGimgDimensions(imgN) {
    return extractImgData(imgN, 'ow') + 'x' + extractImgData(imgN, 'oh');
}

function extractImgData(imgN, key) {
    return extractFromText(getDataText(imgN), key);
}

/** The fallback will be the value returned if no results were found. */
function extractFromText(txt, key, fallback) {
    let data = typeof fallback === undefined ? fallback : ("no image data found for key: '" + key + "'");
    let regex = new RegExp('(?<="' + key + '":")(.+?)(?=")');
    if (!txt) return data;
    let matches = txt.match(regex);
    data = (matches) ? matches[0] : data;
    return data;
}

if (false) window.onbeforeunload = function (e) { // on tab exit
    ublSites = new Set(ublSites, GM_getValue('unblocked sites of og images'));
    console.log('ublSites:', ublSites);
    GM_setValue('unblocked sites of og images', Array.from(ublSites));
    var message = "Saving unblocked sites (confirmation).", e = e || window.event;
    // For IE and Firefox
    if (e) {
        e.returnValue = message;
    }
    // For Safari
    return message;
};

// replaces the image description link text
function replaceImgData(dataEls) {
    if (typeof dataEls === 'undefined') return;
    dataEls.querySelectorAll('.rg_meta').forEach(function (dataEl) {
        if (dataEl.classList.contains('rg_meta-modified')) return;
        try {
            let dataText = dataEl.innerHTML;
            // console.log('modifying meta data text:', dataText);
            let siteUrl = extractFromText(dataText, 'ru');
            let description = extractFromText(dataText, 's');
            let subTitle = extractFromText(dataText, 'st');

            let imageAnchor = dataEl.previousSibling;
            createAndAddAttribute(imageAnchor, 'rg_meta_st', subTitle);
            createAndAddAttribute(imageAnchor, 'rg_meta_ru', siteUrl);

            let hostname = getHostname(siteUrl).replace('www.', '');
            let siteSearchUrl = GoogleImagesSearchURL + "site:" + encodeURIComponent(hostname);

            dataEl.innerHTML = dataEl.innerHTML
                .replace(subTitle, 'site search: ' + hostname) // replace SubTitle text with site HOSTNAME
                .replace(siteUrl, siteSearchUrl) // replace title lin with site siteSearch link
            // .replace(description, HOSTNAME)
            ;

            dataEl.classList.add('rg_meta-modified');
        } catch (exception) {
            console.error("Caught exception while changin rg_meta:", exception);
        }
    });
}

function makeImageDescriptionsClickable() {
    ImagePanel.mainPanel.forEach(function (panel) {
        var description = panel.querySelector('div.irc_b.i8152.irc_mmc > div.i30053 > div > div.irc_it > div.irc_hd > div[dir="ltr"] > font > font');
        description.addEventListener("click", function (e) {
            var search = gImgSearchUrl + this.innerHTML;
            window.open(search, "_blank");
        });
    });
}

unsafeWindow.extractImgData = extractImgData;
unsafeWindow.getGimgTitle = getGimgTitle;
unsafeWindow.getGimgRUrl = getGimgRUrl;
unsafeWindow.getGimgDescription = getGimgDescription;
unsafeWindow.reverseImgSearch = reverseImgSearch;

//[Google.com images]
unsafeWindow.saveUblSites = function () {
    storeSuccessfulUrlsSet();
    console.log('Site links of unblocked images "display-original-image"es:', Array.from(successfulUrlsSet));
};

function addToSet(mainSet, otherSet) {
    if (typeof mainSet === 'undefined' || typeof otherSet === 'undefined') return;
    try {
        // if(isIterable(otherSet) && isIterable(mainSet))
        otherSet.forEach(function (elt, i, a) {
            if (typeof elt === 'string') {
                mainSet.add(elt);
            }
        });
    } catch (exc) {
    }
    console.log('merged sets:', Array.from(mainSet));
    return mainSet;
}

function reverseImgSearch(imageUrl) {
    window.open("https://encrypted.google.com/searchbyimage?&image_url=" + imageUrl, "_blank");
}


/**Here's a vanilla js example to trigger any event:
 *
 <code> triggerEvent(targetElement, 'keyup', 13); // simulate mouse/enter key press</code>*/
function triggerEvent(el, type, keyCode) {
    // focus on the input element
    el.focus();
    if ('createEvent' in document) {
        // modern browsers, IE9+
        var e = document.createEvent('HTMLEvents');
        e.keyCode = keyCode;
        e.initEvent(type, false, true);
        el.dispatchEvent(e);
    } else {
        // IE 8
        var e = document.createEventObject();
        e.keyCode = keyCode;
        e.eventType = type;
        el.fireEvent('on' + e.eventType, e);
    }
}

/* Understanding Google Images
 ###Image Boxes:
 Image boxes are contained in one parent element with the selector: `div#rg_s`.
 Every image box contains an `img`, and a `div` containing the data.


 Attributes |Selector| Notes
 --- | --- | ---
 **img** |
 *ClassName =*| **nicely**

 ###The Image Panel:
 There is one big panel containing 3 sub-panels, you only get to see one sub-panel at a time.
 Moving to the next image will rotate the 3 sub-panels, and you will visit each one as they rotate.
 * Main panel selector: `#irc_cc`
 * Sub-panels contain a `data-ved` attribute, only the active one will have data, the other 2 will be `null`.
 * Active sub-panel selector:    `#irc_cc div.irc_t:not([data-ved="null"])`
 */
class ImageBox extends Element {
}//TODO:
class ImagePanel {
    constructor(element) {
        if (typeof element !== 'undefined') {
            this.element = element;
        }
        this.makeDescriptionClickable();
        // this.relatedImagesDiv = {divElement: this.element,}
    }

    makeDescriptionClickable() {
        this.descriptionEl.addEventListener("click", function (e) {
            const search = gImgSearchUrl + this.innerHTML;
            window.open(search, "_blank");
        });
    }

    get isFocused() {
        return "translate3d(0px, 0px, 0px)".test(this.getAttribute('style'));
    }

    static get mainPanel() {
        const mainPanelEl = q("#irc_cc");
        return mainPanelEl ? new ImagePanel(mainPanelEl) : false;
    }

    get titleAndDescriptionDiv() {
        this.element.querySelector('._cjj > .irc_it');
    }

    /**
     * @returns {ElementTagNameMap[] | Element}
     */
    get descriptionEl() {
        if (this.titleAndDescriptionDiv)
            this.titleAndDescriptionDiv.querySelector('div.irc_hd > div[dir="ltr"] > font > font, div.irc_hd > div[dir="ltr"]');
    }

    get titleEl() {
        if (this.titleAndDescriptionDiv)
            this.titleAndDescriptionDiv.querySelector('span ~ a');
    }

    get title() {
        return this.titleEl.innerHTML;
    }

    get subtitleEl() {
        if (this.titleAndDescriptionDiv)
            this.titleAndDescriptionDiv.querySelector('span a.irc_lth._ZR');
    }

    get subtitle() {
        return this.subtitleEl.innerHTML;
    }

    /**
     * returns that small square at the bottom right (the focused one)
     * @returns {ElementTagNameMap[string] | Element}
     */
    get focusedRelativeImage() {
        return this.element.querySelector('div.irc_rimask.irc_rist');
    }

    get imageUrl() {
        this.focusedRelativeImage.querySelector('a').href;
    }

    get image() {
        return this.element.querySelector('img#irc_mi,img.irc_mut');
    }

    /**
     * @returns {ElementTagNameMap[string] | Element} returns the panel that is currently in focus (there are 3 panels)
     */
    static get focusedPanel() {
        var p = this.mainPanel ? this.mainPanel.querySelector('div.irc_c[style*="translate3d(0px, 0px, 0px)"]') : null;
        console.log('mainPanel:', p);
        return p;
    }

    // TODO: getters:
    // description
    // title
    // subtitle
}

function mainPanel() {
    const mainPanelEl = q("#irc_cc");
    return mainPanelEl;
}

// hot-keys
let KeyEvent;
if (typeof KeyEvent === "undefined") {
    KeyEvent = {
        DOM_VK_SPACE: 32,
        DOM_VK_LEFT: 37,
        DOM_VK_UP: 38,
        DOM_VK_RIGHT: 39,
        DOM_VK_DOWN: 40,
        DOM_VK_A: 65,
        DOM_VK_D: 68,
        DOM_VK_P: 80,
        DOM_VK_Q: 81,
        DOM_VK_R: 82,
        DOM_VK_S: 83,
        DOM_VK_V: 86,
        DOM_VK_W: 87,
        DOM_VK_COMMA: 188,
        DOM_VK_DOT: 190,
        DOM_VK_NUMPAD1: 97,
        DOM_VK_NUMPAD2: 98,
        DOM_VK_NUMPAD3: 99,
        DOM_VK_NUMPAD4: 100,
        DOM_VK_NUMPAD_LEFT: 100,
        DOM_VK_NUMPAD5: 101,
        DOM_VK_NUMPAD6: 102,
        DOM_VK_NUMPAD_RIGHT: 102,
        DOM_VK_NUMPAD7: 103,
        DOM_VK_NUMPAD8: 104,
        DOM_VK_NUMPAD9: 105,
        DOM_VK_NUMPAD_DIVIDE: 106,
        DOM_VK_NUMPAD_MULTIPLY: 111,
        DOM_VK_NUMPAD_ENTER: 113,
        DOM_VK_F5: 116
    };
}

function onkeydown(b) {
    const a = (window.event) ? b.keyCode : b.which;
    /** @type {{CTRL_ONLY: boolean, SHIFT_ONLY: boolean, ALT_ONLY: boolean, NONE: boolean}} */
    const ModifierKeys = {
        CTRL_ONLY: b.ctrlKey && !b.altKey && !b.shiftKey && !b.metaKey,
        SHIFT_ONLY: !b.ctrlKey && !b.altKey && b.shiftKey && !b.metaKey,
        ALT_ONLY: !b.ctrlKey && b.altKey && !b.shiftKey && !b.metaKey,
        NONE: !b.ctrlKey && !b.shiftKey && !b.altKey && !b.metaKey
    };
    // 	if(b.ctrlKey && a == KeyEvent.DOM_VK_S)
    // 	{
    // 		if(i)
    // 		{
    // 			a = protected_createElement("a");
    // 			a.href = i.src;
    // 			a.download = ""; // HTML5
    // 			document.body.appendChild(a);
    // 			a.click();
    // 			document.body.removeChild(a);
    // 		}
    // 		return;
    // 	}
    // 	if (b.altKey || b.metaKey || (b.ctrlKey && a != KeyEvent.DOM_VK_SPACE && a != KeyEvent.DOM_VK_F5 && a != KeyEvent.DOM_VK_R))
    // 	{
    // 		return;
    // 	}

    // 	var by = Math.round(window.innerHeight * 0.10);

    const panel = mainPanel().querySelector('div.irc_c[style*="translate3d(0px, 0px, 0px)"]'); //ImagePanel.focusedPanel; // the active panel
    if (!panel) {
        console.error("SUBPANEL NOT FOUND!!");
        return false;
    }
    const focusedRelatedImage = panel.querySelector('div.irc_rimask.irc_rist');//panel.focusedRelativeImage;

    const panelImage = panel.querySelector('img#irc_mi,img.irc_mut');
    /**
     * @type {any | NodeListOf<Element>}
     * 0 - Visit
     * 1 - Save
     * 2 - View saved
     * 3 - Share
     */
    const buttons = panel.querySelectorAll('.irc_but_r > tbody > tr a');

    const visitPageButton = buttons[0];
    const titleAndDescriptionDiv = panel.querySelector('._cjj > .irc_it');
    const titleEl = titleAndDescriptionDiv.querySelector('span ~ a');
    const subtitleEl = titleAndDescriptionDiv.querySelector('span a.irc_lth._ZR');

    log("titleAndDescriptionDiv:", titleAndDescriptionDiv);
    if (!titleEl) console.error("Title element not found");
    if (!subtitleEl) console.error("SubTitle element not found");
    const title = titleEl.innerHTML;
    // panel.querySelector('a._ZR.irc_hol.i3724.irc_lth');
    const subtitle = subtitleEl.innerHTML;

    // image drop-down panel:    #irc_bg
    /**Goes to the previous main image*/
    function previousImage() {
        // triggerEvent(q("#irc_bg"), "keyup", KeyEvent.DOM_VK_LEFT);
        q('#irc_la').click();
    }

    /**Goes to the next main image*/
    function nextImage() {
        // triggerEvent(q("#irc_bg"), "keyup", KeyEvent.DOM_VK_LEFT);
        q('#irc_ra').click();
    }

    function lookupTitle() {
        const extractedTitleSearchText = (title.length < subtitle.length ? subtitle : title); // use the longer title
        openInTab(GoogleReverseImagesSearchURL + extractedTitleSearchText);
    }

    function siteSearch() {
        const hostname = getHostname(subtitleEl.href);
        console.log('Site search:', hostname);
        openInTab(siteSearchUrl(getHostname(subtitleEl.href)));
    }

    switch (a) {
        // Search by image/ site search
        case KeyEvent.DOM_VK_V:
        case KeyEvent.DOM_VK_NUMPAD1:
            const focusedRelatedImageUrl = focusedRelatedImage.querySelector('a').href;
            console.log('currentPanelImage', focusedRelatedImageUrl);
            if (typeof panelImage !== "undefined") {
                reverseImgSearch(focusedRelatedImageUrl);
                log("focusedRelatedImageUrl:", focusedRelatedImageUrl);
            } else
                console.error('Image not found', focusedRelatedImageUrl);
            break;
        // TODO:
        case KeyEvent.DOM_VK_NUMPAD4:
            nextImage();
            break;
        case KeyEvent.DOM_VK_NUMPAD6:
            previousImage();
            break;
        // Open related images (press the bottom right square in the corner) in new tab
        case KeyEvent.DOM_VK_NUMPAD3:
            const moreRelatedImagesLink = q('.irc_rismo.irc_rimask a');
            if (typeof moreRelatedImagesLink !== 'undefined')
                openInTab(moreRelatedImagesLink.href);
            break;
        case KeyEvent.DOM_VK_NUMPAD5:
            if (ModifierKeys.NONE) {
                openInTab(focusedRelatedImage.querySelector('a').href);
            } else if (ModifierKeys.CTRL_ONLY) {
                download(focusedRelatedImage.querySelector('a').href, undefined, undefined, focusedRelatedImage);
            }
            break;
        // Previous related image
        case KeyEvent.DOM_VK_COMMA:
        case KeyEvent.DOM_VK_NUMPAD8:
            let previousElementSibling = focusedRelatedImage.previousElementSibling;
            (previousElementSibling) ?
                previousElementSibling.click() :
                previousImage();
            break;
        // Next related image
        case KeyEvent.DOM_VK_DOT:
        case KeyEvent.DOM_VK_NUMPAD2:
            let nextElementSibling = focusedRelatedImage.nextElementSibling;
            (nextElementSibling && !nextElementSibling.classList.contains('irc_rismo')) ?
                nextElementSibling.click() :
                nextImage();
            break;
        // lookup the images title.
        // Opens a new window with the search query as the image title
        case KeyEvent.DOM_VK_NUMPAD7:
            // I have options, I'll choose the best later
            const visitUrl = buttons[0].href;
            const visitTitleUrl = subtitleEl.href;

            console.log('Visit:', visitUrl);
            openInTab(visitUrl);
            break;
        //TODO: Search using title
        //TODO: Visit website/ GIMG Site.Search the website
        case KeyEvent.DOM_VK_NUMPAD9:
            if (ModifierKeys.NONE) {
                lookupTitle();
            } else if (ModifierKeys.CTRL_ONLY) { // site search
                siteSearch();
            }
            break;

        case KeyEvent.DOM_VK_S:
            siteSearch();
            break;
    }

}

function openInTab(url) {
    window.open(url, "_blank");
}

// data-cthref = /url?sa=i&rct=j&q=&esrc=s&source=images&cd=&ved=2ahUKEwjW84KFwbzZAhUvT98KHX4fA6UQjB16BAgAEAU&url=http%3A%2F%2Frwby.wikia.com%2Fwiki%2FFile%3ATEAM_PAJAMA_RWBY!.jpg&psig=AOvVaw2HgCMglmhtGPN4QfLzDi4P&ust=1519491410121543



QingJ © 2025

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