danieljbingham / google-image-sizer

Chrome extension to re-implement Google Images size filter (e.g. Larger than 2MP)
15 stars 3 forks source link

Cyrillic Encoding problem #9

Closed GrayWolfson closed 4 years ago

GrayWolfson commented 4 years ago

In Firefox (v72)

There was a request – "орошаемое земледелие"

after choosing a 2MP size, for example, the request looks like this – "орошаемое земледелие"

Procyon-b commented 4 years ago

@GrayWolfson Here is a fix.

@danieljbingham could you test too? In this version the script only unescapes the "tbs=" parameter instead of the whole string. This is done in 2 lines, because in a .replace() you can't unescape() a literal "$1" or use RegExp.$1 (not yet populated)

// ==UserScript==
// @name         Google image sizer
// @namespace    https://github.com/danieljbingham/google-image-sizer
// @version      1.0.3.6
// @description  re-implement Google Images size filter
// @author       Daniel Bingham
// @include      http*://*.google.tld/search*tbm=isch*
// @grant        none
// ==/UserScript==

(function () {

    var sz = /[?&]tbs=(?:[^&]+,)?isz(?::|%3A)([^&,]+)(?:,islt(?::|%3A)([^&,]+))?/.exec(location.search) || [];
    var sizes = [["isz_2", "2mp"], ["isz_4", "4mp"], ["isz_6", "6mp"], ["isz_8", "8mp"], ["isz_10", "10mp"],
    ["isz_12", "12mp"], ["isz_15", "15mp"], ["isz_20", "20mp"], ["isz_40", "40mp"], ["isz_70", "70mp"]];

    /*
    Add sizes for one of two possibilities for the Google Images layout
    */
    function addSizes() {
        var e;
        if (document.getElementById('isz_i')) {
            addSizesIsz();
        }
        else if (e=document.querySelector('.qcTKEe')) {
            e=e.querySelector(':scope [data-index="0"]');
            const obs = new MutationObserver(function(mutL){
                for (let mut of mutL) {
                    if ((mut.type=='attributes') && (mut.attributeName=='class') && mut.target.classList.contains('iWO5td')) {
                        addSizesGCard();
                        return;
                        }
                    }
                });
            obs.observe(e.parentNode, {subtree: true, attributes: true} );
            }
        else {
            addSizesOnClick();
        }
    }

    /*
    Iterate through list of image sizes and add them to the DOM (when 'isz' elements are present)
    */
    function addSizesIsz() {
        var icon = document.getElementById("isz_i").parentNode.querySelector(':scope * + .hdtbItm:not([tabindex])');
        var parent = icon.parentNode;
        var clone, child, chkAny = false;
        for (var i = 0; i < sizes.length; i++) {
            clone = icon.cloneNode(true);
            clone.id = sizes[i][0];
            if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) {
                clone.classList.add('hdtbSel');
                child = clone;
                chkAny = true;
                parent.previousSibling.querySelector('.mn-hd-txt').textContent = "Larger than " + sizes[i][1].toUpperCase();
                parent.previousSibling.classList.add('hdtb-tsel');
            }
            else {
                child = clone.firstChild;
                child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]);
            }
            child.textContent = "Larger than " + sizes[i][1].toUpperCase();

            parent.appendChild(clone);
        }

        var fc = parent.firstElementChild;
        if (chkAny && fc.classList.contains('hdtbSel')) {
            fc.classList.remove('hdtbSel');
            child = icon.firstChild.cloneNode(true);
            child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)/, "$1");
            child.textContent = fc.textContent;
            fc.textContent = '';
            fc.appendChild(child);
        }
    }

  // alternative version of layout
    function addSizesGCard() {
        var icon = document.querySelector(':scope .irf0hb > .Ix6LGe > a[href*="tbs="][href*="isz"]');
        var parent = icon.parentNode;
        if (parent.classList.contains('szDone')) return;
        parent.classList.add('szDone');
        icon.href.search(/(tbs=[^&]*)/);
        icon.href = icon.href.replace(/(tbs=[^&]*)/, unescape(RegExp.$1) );
        var cur = parent.querySelector('span.MfLWbb');
        for (var i = 0; i < sizes.length; i++) {
            let clone = icon.cloneNode(true);
            clone.id = sizes[i][0];
            if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) {
                parent.removeChild(cur);
                clone=cur;
            }
            else {
                clone.href = clone.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]);
                let al = clone.firstChild.firstChild.textContent = "Larger than " + sizes[i][1].toUpperCase();
                if (clone.attributes['aria-label']) clone.attributes['aria-label'].value = al;
            }
            parent.appendChild(clone);
        }
    }

    /*
    When sizes nav is not already present in source code, add an event listener to add sizes when the menu is clicked
    */
    function addSizesOnClick() {
        document.getElementById("hdtb-tls").addEventListener("click", function(){
            document.querySelectorAll('[aria-label="Size"]').item(0).addEventListener("click", function(){
                addSizesIsz();
            });
        });
    }

    /*
    Check the user is on google images
    */
    function isImageUrl() {
        return location.href.includes("tbm=isch");
    }

    /*
    Check sizes not there already
    */
    function needSizes() {
        var nodes = document.querySelector('[aria-label="Large"]') || document.getElementById("isz_i"); 
        if (nodes) return nodes.parentNode.childNodes.length < 6;
        else return document.querySelector('.qcTKEe') && true;
    }

    /*
    Show sizes/dimensions by default instead of on hover
    */
    function showSizesDefault() {
        var css = ".rg_anbg {display: none !important;} .rg_l:hover .rg_anbg {display: block !important;} " +
            ".rg_ilmbg {display: block !important;} .rg_l:hover .rg_ilmbg {display: none !important;}" +
            ".h312td.RtIwE {display:block;} .isv-r.MSM1fd:hover .h312td.RtIwE {display: none;}";
        var style = document.createElement('style');

        if (style.styleSheet) {
            style.styleSheet.cssText = css;
        } else {
            style.appendChild(document.createTextNode(css));
        }

        document.getElementsByTagName('head')[0].appendChild(style);
    }

    //run script
    showSizesDefault();

    //somewhere: document.querySelectorAll('[role="listitem"]').item(0).addEventListener()

    var maxTries = 100;
    function chk() {
        if (!document.getElementById('isz_i') && (!document.querySelector('[aria-label="Large"]')) && (!document.querySelector('.qcTKEe'))) {
            if (maxTries--) setTimeout(chk, 100);
            return;
        }
        if (needSizes()) addSizes();
    }

    if (isImageUrl()) chk();

})();
GrayWolfson commented 4 years ago

It worked perfectly. Thanks!

Procyon-b commented 4 years ago

@danieljbingham In fact unescape() can be used in replace() but in a function(){} parameter. Here is an updated version, with another fix in the first var declaration. unescape() also added there to catch the current size.

// ==UserScript==
// @name         Google image sizer
// @namespace    https://github.com/danieljbingham/google-image-sizer
// @version      1.0.3.6
// @description  re-implement Google Images size filter
// @author       Daniel Bingham
// @include      http*://*.google.tld/search*tbm=isch*
// @grant        none
// ==/UserScript==

(function () {

    var sz = /[?&]tbs=(?:[^&]+,)?isz(?::|%3A)([^&,]+)(?:,islt(?::|%3A)([^&,]+))?/.exec(unescape(location.search)) || [];
    var sizes = [["isz_2", "2mp"], ["isz_4", "4mp"], ["isz_6", "6mp"], ["isz_8", "8mp"], ["isz_10", "10mp"],
    ["isz_12", "12mp"], ["isz_15", "15mp"], ["isz_20", "20mp"], ["isz_40", "40mp"], ["isz_70", "70mp"]];

    /*
    Add sizes for one of two possibilities for the Google Images layout
    */
    function addSizes() {
        var e;
        if (document.getElementById('isz_i')) {
            addSizesIsz();
        }
        else if (e=document.querySelector('.qcTKEe')) {
            e=e.querySelector(':scope [data-index="0"]');
            const obs = new MutationObserver(function(mutL){
                for (let mut of mutL) {
                    if ((mut.type=='attributes') && (mut.attributeName=='class') && mut.target.classList.contains('iWO5td')) {
                        addSizesGCard();
                        return;
                        }
                    }
                });
            obs.observe(e.parentNode, {subtree: true, attributes: true} );
            }
        else {
            addSizesOnClick();
        }
    }

    /*
    Iterate through list of image sizes and add them to the DOM (when 'isz' elements are present)
    */
    function addSizesIsz() {
        var icon = document.getElementById("isz_i").parentNode.querySelector(':scope * + .hdtbItm:not([tabindex])');
        var parent = icon.parentNode;
        var clone, child, chkAny = false;
        for (var i = 0; i < sizes.length; i++) {
            clone = icon.cloneNode(true);
            clone.id = sizes[i][0];
            if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) {
                clone.classList.add('hdtbSel');
                child = clone;
                chkAny = true;
                parent.previousSibling.querySelector('.mn-hd-txt').textContent = "Larger than " + sizes[i][1].toUpperCase();
                parent.previousSibling.classList.add('hdtb-tsel');
            }
            else {
                child = clone.firstChild;
                child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]);
            }
            child.textContent = "Larger than " + sizes[i][1].toUpperCase();

            parent.appendChild(clone);
        }

        var fc = parent.firstElementChild;
        if (chkAny && fc.classList.contains('hdtbSel')) {
            fc.classList.remove('hdtbSel');
            child = icon.firstChild.cloneNode(true);
            child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)/, "$1");
            child.textContent = fc.textContent;
            fc.textContent = '';
            fc.appendChild(child);
        }
    }

  // alternative version of layout
    function addSizesGCard() {
        var icon = document.querySelector(':scope .irf0hb > .Ix6LGe > a[href*="tbs="][href*="isz"]');
        var parent = icon.parentNode;
        if (parent.classList.contains('szDone')) return;
        parent.classList.add('szDone');
        icon.href = icon.href.replace(/(tbs=[^&]*)/, function(s){return unescape(s)} );
        var cur = parent.querySelector('span.MfLWbb');
        for (var i = 0; i < sizes.length; i++) {
            let clone = icon.cloneNode(true);
            clone.id = sizes[i][0];
            if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) {
                parent.removeChild(cur);
                clone=cur;
            }
            else {
                clone.href = clone.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]);
                let al = clone.firstChild.firstChild.textContent = "Larger than " + sizes[i][1].toUpperCase();
                if (clone.attributes['aria-label']) clone.attributes['aria-label'].value = al;
            }
            parent.appendChild(clone);
        }
    }

    /*
    When sizes nav is not already present in source code, add an event listener to add sizes when the menu is clicked
    */
    function addSizesOnClick() {
        document.getElementById("hdtb-tls").addEventListener("click", function(){
            document.querySelectorAll('[aria-label="Size"]').item(0).addEventListener("click", function(){
                addSizesIsz();
            });
        });
    }

    /*
    Check the user is on google images
    */
    function isImageUrl() {
        return location.href.includes("tbm=isch");
    }

    /*
    Check sizes not there already
    */
    function needSizes() {
        var nodes = document.querySelector('[aria-label="Large"]') || document.getElementById("isz_i"); 
        if (nodes) return nodes.parentNode.childNodes.length < 6;
        else return document.querySelector('.qcTKEe') && true;
    }

    /*
    Show sizes/dimensions by default instead of on hover
    */
    function showSizesDefault() {
        var css = ".rg_anbg {display: none !important;} .rg_l:hover .rg_anbg {display: block !important;} " +
            ".rg_ilmbg {display: block !important;} .rg_l:hover .rg_ilmbg {display: none !important;}" +
            ".h312td.RtIwE {display:block;} .isv-r.MSM1fd:hover .h312td.RtIwE {display: none;}";
        var style = document.createElement('style');

        if (style.styleSheet) {
            style.styleSheet.cssText = css;
        } else {
            style.appendChild(document.createTextNode(css));
        }

        document.getElementsByTagName('head')[0].appendChild(style);
    }

    //run script
    showSizesDefault();

    //somewhere: document.querySelectorAll('[role="listitem"]').item(0).addEventListener()

    var maxTries = 100;
    function chk() {
        if (!document.getElementById('isz_i') && (!document.querySelector('[aria-label="Large"]')) && (!document.querySelector('.qcTKEe'))) {
            if (maxTries--) setTimeout(chk, 100);
            return;
        }
        if (needSizes()) addSizes();
    }

    if (isImageUrl()) chk();

})();
danieljbingham commented 4 years ago

Thanks a lot for taking care of this, I've been swamped so wasn't able to take a look. I'll test everything on my end tomorrow and then update the extension on the chrome/firefox stores.

On 23 Feb 2020, at 00:24, Marc Boucher notifications@github.com wrote:

@danieljbingham In fact unescape() can be used in replace() but in a function(){} parameter. Here is an updated version, with another fix in the first var declaration. unescape() also added there to catch the current size.

// ==UserScript== // @name Google image sizer // @namespace https://github.com/danieljbingham/google-image-sizer // @version 1.0.3.6 // @description re-implement Google Images size filter // @author Daniel Bingham // @include http://.google.tld/searchtbm=isch // @grant none // ==/UserScript==

(function () {

var sz = /[?&]tbs=(?:[^&]+,)?isz(?::|%3A)([^&,]+)(?:,islt(?::|%3A)([^&,]+))?/.exec(unescape(location.search)) || []; var sizes = [["isz_2", "2mp"], ["isz_4", "4mp"], ["isz_6", "6mp"], ["isz_8", "8mp"], ["isz_10", "10mp"], ["isz_12", "12mp"], ["isz_15", "15mp"], ["isz_20", "20mp"], ["isz_40", "40mp"], ["isz_70", "70mp"]];

/ Add sizes for one of two possibilities for the Google Images layout / function addSizes() { var e; if (document.getElementById('isz_i')) { addSizesIsz(); } else if (e=document.querySelector('.qcTKEe')) { e=e.querySelector(':scope [data-index="0"]'); const obs = new MutationObserver(function(mutL){ for (let mut of mutL) { if ((mut.type=='attributes') && (mut.attributeName=='class') && mut.target.classList.contains('iWO5td')) { addSizesGCard(); return; } } }); obs.observe(e.parentNode, {subtree: true, attributes: true} ); } else { addSizesOnClick(); } }

/ Iterate through list of image sizes and add them to the DOM (when 'isz' elements are present) / function addSizesIsz() { var icon = document.getElementById("isz_i").parentNode.querySelector(':scope * + .hdtbItm:not([tabindex])'); var parent = icon.parentNode; var clone, child, chkAny = false; for (var i = 0; i < sizes.length; i++) { clone = icon.cloneNode(true); clone.id = sizes[i][0]; if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) { clone.classList.add('hdtbSel'); child = clone; chkAny = true; parent.previousSibling.querySelector('.mn-hd-txt').textContent = "Larger than " + sizes[i][1].toUpperCase(); parent.previousSibling.classList.add('hdtb-tsel'); } else { child = clone.firstChild; child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]); } child.textContent = "Larger than " + sizes[i][1].toUpperCase();

      parent.appendChild(clone);
  }

  var fc = parent.firstElementChild;
  if (chkAny && fc.classList.contains('hdtbSel')) {
      fc.classList.remove('hdtbSel');
      child = icon.firstChild.cloneNode(true);
      child.href = child.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)/, "$1");
      child.textContent = fc.textContent;
      fc.textContent = '';
      fc.appendChild(child);
  }

}

// alternative version of layout function addSizesGCard() { var icon = document.querySelector(':scope .irf0hb > .Ix6LGe > a[href="tbs="][href="isz"]'); var parent = icon.parentNode; if (parent.classList.contains('szDone')) return; parent.classList.add('szDone'); icon.href = icon.href.replace(/(tbs=[^&]*)/, function(s){return unescape(s)} ); var cur = parent.querySelector('span.MfLWbb'); for (var i = 0; i < sizes.length; i++) { let clone = icon.cloneNode(true); clone.id = sizes[i][0]; if ((sz[1]=='lt') && (sizes[i][1] == sz[2]) ) { parent.removeChild(cur); clone=cur; } else { clone.href = clone.href.replace(/(tbs=(?:[^&]+,)?)isz(:[^&,]+)(?:,islt:([^&,]+))?/, "$1" + "isz:lt,islt:" + sizes[i][1]); let al = clone.firstChild.firstChild.textContent = "Larger than " + sizes[i][1].toUpperCase(); if (clone.attributes['aria-label']) clone.attributes['aria-label'].value = al; } parent.appendChild(clone); } }

/ When sizes nav is not already present in source code, add an event listener to add sizes when the menu is clicked / function addSizesOnClick() { document.getElementById("hdtb-tls").addEventListener("click", function(){ document.querySelectorAll('[aria-label="Size"]').item(0).addEventListener("click", function(){ addSizesIsz(); }); }); }

/ Check the user is on google images / function isImageUrl() { return location.href.includes("tbm=isch"); }

/ Check sizes not there already / function needSizes() { var nodes = document.querySelector('[aria-label="Large"]') || document.getElementById("isz_i"); if (nodes) return nodes.parentNode.childNodes.length < 6; else return document.querySelector('.qcTKEe') && true; }

/ Show sizes/dimensions by default instead of on hover / function showSizesDefault() { var css = ".rg_anbg {display: none !important;} .rg_l:hover .rg_anbg {display: block !important;} " + ".rg_ilmbg {display: block !important;} .rg_l:hover .rg_ilmbg {display: none !important;}" + ".h312td.RtIwE {display:block;} .isv-r.MSM1fd:hover .h312td.RtIwE {display: none;}"; var style = document.createElement('style');

  if (style.styleSheet) {
      style.styleSheet.cssText = css;
  } else {
      style.appendChild(document.createTextNode(css));
  }

  document.getElementsByTagName('head')[0].appendChild(style);

}

//run script showSizesDefault();

//somewhere: document.querySelectorAll('[role="listitem"]').item(0).addEventListener()

var maxTries = 100; function chk() { if (!document.getElementById('isz_i') && (!document.querySelector('[aria-label="Large"]')) && (!document.querySelector('.qcTKEe'))) { if (maxTries--) setTimeout(chk, 100); return; } if (needSizes()) addSizes(); }

if (isImageUrl()) chk();

})(); — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

Procyon-b commented 4 years ago

@danieljbingham don't forget about it. ;)

danieljbingham commented 4 years ago

@Procyon-b Haha, thank you, I've just pushed the new code