Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest version (1.5.0.19) #95

Open
Procyon-b opened this issue Mar 16, 2020 · 32 comments
Open

Latest version (1.5.0.19) #95

Procyon-b opened this issue Mar 16, 2020 · 32 comments

Comments

@Procyon-b
Copy link
Contributor

Procyon-b commented Mar 16, 2020

This is the lastest version. It contains a small fix to display the "search by image link" on the side-panel.

I post this in a new thread to make it easier to locate for newcomers.

The code in my fork has been updated. Those still using this as a source for the userscript in tampermonkey will be updated automatically.

Here is the method to use it that way:
Those who want to have the script automatically updated from my fork can use the "Raw" button on the script page. Tampermonkey detects that it is a userscript, and proposes to install it. And it will automatically be updated when a newer version appears.

// @version         1.5.0.11

look below for lastest version

@pilaco
Copy link

pilaco commented Mar 26, 2020

google.com.br was not working so i add this:
const lang = { br: 'Ver imagem',
srch = { br: 'Pesquisar por imagem',

@Procyon-b
Copy link
Contributor Author

Procyon-b commented Mar 26, 2020

When I try google.com.br with chrome configured to use portuguese/brazil as the main language, I receive google image results in portuguese with this script correctly identifying the language.

The script gets it from the tag <html lang="pt" ...> :
const pgL=document.documentElement.lang;

Looking at the source code of the results' page, what do you see as the "lang" attribute of the html tag?

I don't think that adding {br: ...} to the 2 objects has fixed your issue. It's probably that the page had a temporary problem. But I'll wait to see what parameter you get to confirm this.

@pilaco
Copy link

pilaco commented Mar 27, 2020

Appears that way without the const lang = { br: 'Ver imagem', srch = { br: 'Pesquisar por imagem',
image
and that way with the parameters
image

Looking at the source code of the results' page, what do you see as the "lang" attribute of the html tag?

source code <!doctype html><html lang="pt"

I don’t know why it happens, but it works when I put the const lang = {br: 'See image' parameters, srch = {br: 'Search by image', . I always had to put these parameters

@Procyon-b
Copy link
Contributor Author

Do you see any error message in the console when using the unmodified script?
With the logic implemented, even if it can't find a matching definition for the language used, it defaults to "en". But from what I see in your screenshot, it fails to display the modifications. So the script fails somewhere...

What browser are you using ?

@pilaco
Copy link

pilaco commented Mar 27, 2020

Do you see any error message in the console when using the unmodified script?

No
image

What browser are you using ?

Chromium Versão 74.0.3729.169 (Versão oficial) Arch Linux 32 32 bits

I tested it on firefox 69.0.1 (32-bit) with the code unmodified and it worked.

Do you think that if I clear the cache it could work?

@Procyon-b
Copy link
Contributor Author

I pretty sure clearing won't solve the issue.
The problem is that, whatever the language is, the script should run correctly. The button and the link should appear. In your case they don't when you haven't edited the script.
I'll look at it, and make a special version with console comments, to understand what is happening.

Which extension are you using to run the script? Tampermonkey?

How have you installed the script?
Cut and paste from this issue? Or from the raw file in my fork?
I'm wondering if something could be lost/broken in a cut & paste regarding the utf8 chars. This could be the reason, unless you leave all other language strings untouched when adding {br:.

@pilaco
Copy link

pilaco commented Mar 27, 2020

Which extension are you using to run the script?

Violentmonkey

How have you installed the script?

I installed from the url Google Search "View Image" Button

Cut and paste from this issue? Or from the raw file in my fork?

raw file from your fork

it's weird because it works on firefox but it doesn't work on chromium

@Procyon-b
Copy link
Contributor Author

I've tried wth Violentmonkey in a test profile, and I have no problem with the script.
Really weird.
We've already seen users having problem running the script when google was using new/test layouts. But it's not your case, since modifying the script "solves" the problem.

Are there different values for the counter displayed on VM icon with and without your modification?

@Procyon-b
Copy link
Contributor Author

I can suggest some more tests:

  • create a new profile: install Violentmonkey + the script
  • (if previous test fails) with tampermonkey + the script

@pilaco
Copy link

pilaco commented Mar 27, 2020

I created a new profile and it worked!

@Procyon-b
Copy link
Contributor Author

OK,
Now, fixing your problem...

  • Check if your settings in Violentmonkey are the same as in the new profile.
  • Try uninstalling/reinstalling the script
  • try disabling other scripts
  • You can also disable other extensions and see if one of them is causing a conflict.

@Procyon-b
Copy link
Contributor Author

Procyon-b commented Apr 21, 2020

Fix for the color of "search by image" link. (darkgray on black background isn't really visible ;) )

Since this is a small fix, I'll update my fork immediately.

// @version         1.5.0.12

look below for lastest version

@Procyon-b Procyon-b changed the title Latest version (1.5.0.11) Latest version (1.5.0.12) Apr 21, 2020
@NightLancer
Copy link

Thanks man!
I hated that Google has removed 2 such a useful things - original opening and size dimensions, and today I've restored both of it using two simple userscripts. Why have I tolerated it all that time?

It is sad, that "updates" not always bring some good stuff, but sometimes ruin old good stuff, but it is great there are people that can bring back what is useful)

@Procyon-b
Copy link
Contributor Author

I don't know why they are always messing up with their layout and features.
After the image page they also changed the text search result blocs layout. I also had to fix that. :)

We've a saying in french, something like "it's changing for changing". (no other purpose than the change itself)

@B00ze64
Copy link

B00ze64 commented Jun 29, 2020

Salut Marc @Procyon-b

This is not working for me with that new "Side Panel" layout on Google. I'm using Violent Monkey in Firefox 77. Could it be the issue where CSP is preventing script injection? VM says the script is active, but no Show button :-(

Best Regards,

@Procyon-b
Copy link
Contributor Author

Salut @B00ze64
I've tested with FF 77.0.1 and VM 2.12.7, and everything works as expected.
What do you call "Side Panel" ?
Is it the current layout that you can see in the screenshots above, or has google introduced a new layout?

@B00ze64
Copy link

B00ze64 commented Jun 29, 2020

Salut @Procyon-b, alors suite a ton commentaire, je teste avec un nouveau profil, et ça marche! Ah ben maudit! Alors je re-teste avec mes 2 autres profils et ça marche aussi! Je te dis, hier ça fonctionnait pas, estie! lol. C'est plein de situations comme ça avec Firefox, des fois y'a des trucs qui fonctionnent pas pour aucune raison apparente. Merci de continuer à mettre à jour ton script, c'est pas facile d'en trouver un à jour. Y'a 50 FORKs du script ici, et pas un (sauf le tiens) est gardé à jour. PS: Tu pourrais activer les "Issues" sur ton Fork, tant qu'à utiliser le issue tracker de quelqu'un d'autre. PPS: Le "Side Panel" c'est le "nouveau" layout de Google où l'image apparaît à la droite - pour moi c'est nouveau parce que je fais des recherches d'images seulement quelques fois par année. Allez, merci encore! A+

EDIT: For all English Speakers -> No worries, script works, my bad.

@Procyon-b
Copy link
Contributor Author

C'est plein de situations comme ça avec Firefox, des fois y'a des trucs qui fonctionnent pas pour aucune raison apparente.
Je sais bien que dans chrome l'explication peut être qu'un extension à priorité sur une autre et peut contrecarrer le fonctionnement de l'autre. J'imagine que le même genre de problème est aussi probable dans FF.

J'ai aussi déjà eu (dans chrome) des problèmes (avec tampermonkey par ex.) où redémarrer le navigateur était indispensable pour rétablir le comportement normal.

A noter que, par défaut, chrome a une option qui lui permet de continuer à tourner même après l'avoir fermé (une option dont l'intitulé est du genre "Continue running background apps when Google Chrome is closed"). Et donc, dans ce cas, fermer et redémarrer chrome ne fait pas vraiment ce à quoi on s'attend, puisqu'il n'est pas vraiment arrêté.
Tout ça pour dire que FF a peut-être le même comportement. Je n'utilise pas FF en temps normal, et donc je n'ai pas fouillé dans les options.

Merci de continuer à mettre à jour ton script, c'est pas facile d'en trouver un à jour. Y'a 50 FORKs du script ici, et pas un (sauf le tiens) est gardé à jour. PS: Tu pourrais activer les "Issues" sur ton Fork, tant qu'à utiliser le issue tracker de quelqu'un d'autre.

Je me suis dévoué quand j'ai vu que @devunt n'avait pas le temps de s'occuper des mises à jour. :)
Je n'ai volontairement pas activé les issues sur mon fork pour garder les contacts centralisés ici, sur le repository d'origine. Mais il est vrai que devunt n'est plus passé ici depuis un certain temps. Et que l'extension, elle, n'est plus mise à jour du tout.

@B00ze64
Copy link

B00ze64 commented Jun 30, 2020

Salut!

C'est exactement ce que je pense, le "Multi-Process" (exécution non-synchronisée) cause des problèmes parce que dans Firefox il y a des endroits où plusieurs extensions peuvent modifier une requête/page (comme par exemple les Headers) et la première qui y touche gagne sur les autres. Ils ont corrigé ça à certains endroits mais pas partout. Il y a d'autres problèmes aussi; Firefox est en retard sur Chrome, et c'est long de faire corriger des bugs; ils travaillent surtout à rattraper Chrome hehe.

Pour ton fork, c'est correct si tu préfères utiliser le repo d'origine, tant qu'à être obligé de changer de nom etc. L'extension n'est même plus sur le site de Mozilla, lol. Il y en a une autre (https://addons.mozilla.org/en-US/firefox/addon/view-image/) mais elle souffre du même problème, c-a-d que l'auteur ne la garde pas tout à fait à jour. Elle ne fonctionne qu'à demie.

Enouka, merci d'être ici, c'est pratique ce bouton View Image! :-)

@Procyon-b
Copy link
Contributor Author

Procyon-b commented Oct 26, 2020

Fixes to ensure the original full-size image is used.
The code in my fork is updated. Those using it don't have to do anything.

// @version         1.5.0.14

Latest version is below

@Procyon-b Procyon-b changed the title Latest version (1.5.0.12) Latest version (1.5.0.14) Oct 26, 2020
@Procyon-b
Copy link
Contributor Author

Procyon-b commented Mar 21, 2021

Another variation of the layout has appeared.

// @version         1.5.0.15

Latest version is below

@Procyon-b Procyon-b changed the title Latest version (1.5.0.14) Latest version (1.5.0.15) Mar 21, 2021
@Procyon-b
Copy link
Contributor Author

Procyon-b commented Jul 30, 2021

name of a style has changed

// @version         1.5.0.16

@Procyon-b Procyon-b changed the title Latest version (1.5.0.15) Latest version (1.5.0.16) Jul 30, 2021
@Procyon-b Procyon-b changed the title Latest version (1.5.0.16) Latest version (1.5.0.17) May 30, 2022
@Procyon-b
Copy link
Contributor Author

Procyon-b commented May 30, 2022

Long time no see...

Noticed today that our button wasn't there. Just a classname changed.

// @version         1.5.0.17

Latest version is below

@ftc2
Copy link

ftc2 commented Mar 15, 2023

@Procyon-b i think it broke again. please save us. 🙏

also you might as well set the script homepage to your fork. and the update url. you're the man.

@Procyon-b
Copy link
Contributor Author

Procyon-b commented Mar 17, 2023

@ftc2 you're lucky. I was able to reproduce only with my current cookies. Whenever I tried to trigger this layout variation with other cookies/TLDs the button was added.

I keep the original homepage because issues are here, but I've added the updateurl of my fork. Those who have added the script from that url are already updated automatically.

The fix is as usual just a classname change.

// @version         1.5.0.18

Latest version is below

@ftc2
Copy link

ftc2 commented Mar 17, 2023

awesome, thanks!

I keep the original homepage because issues are here, but I've added the updateurl of my fork. Those who have added the script from that url are already updated automatically.

@updateURL is still missing from your fork though. it's in what you pasted above, but i think you forgot to add it to your repo.

@Procyon-b
Copy link
Contributor Author

@updateURL is still missing from your fork though. it's in what you pasted above, but i think you forgot to add it to your repo.

It isn't needed because the script is already located at the right place. Every userscripts managers I've tested (3 or 4) uses either the updateURL or the script installation location to check for updates. Am I missing something?

@ftc2
Copy link

ftc2 commented Mar 18, 2023

i had no idea! i thought updateURL was needed for updates.

@Procyon-b
Copy link
Contributor Author

It's useful when you host the code on different servers and want to direct every update to one copy/server only.

@Procyon-b
Copy link
Contributor Author

Two new designs for the buttons are currently tested.
Here is a new version to handle these cases

// ==UserScript==
// @name            Google Search "View Image" Button
// @name:ru         Google Search кнопка "Показать в полном размере"
// @name:sl         Gumb "Ogled slike" na Google Slikah
// @name:uk         Google Search кнопка "Показати зображення"
// @name:lt         Google paieškos mygtukas "Rodyti vaizdą"
// @name:pl         Przycisk "Pokaż obraz" w wyszukiwarce obrazów Google
// @name:ja         Google 検索「画像を表示」ボタン
// @name:ko         Google 검색 ‘이미지 보기’ 버튼
// @name:nl         Google zoeken "Afbeelding bekijken" knop
// @name:sk         Tlačidlo "Zobraziť obrázok" pre Google Search
// @name:tr         Google Görseller "Resmi Görüntüle" butonu
// @namespace       https://github.com/devunt/make-gis-great-again
// @icon            https://raw.githubusercontent.com/devunt/make-gis-great-again/master/icons/icon.png
// @version         1.5.0.19
// @description     This userscript adds "View Image" button to Google Image Search results.
// @description:ru  Этот скрипт добавляет кнопку "Показать в полном размере" к результатам Google Image Search.
// @description:sl  Ponovno prikaže gumb "Ogled slike" na Google Slikah.
// @description:uk  Цей скрипт додає кнопку "Показати зображення" до результатів Google Image Search.
// @description:lt  Šis vartotojo skriptas prideda mygtuką "Rodyti vaizdą" į Google vaizdo paieškos rezultatus.
// @description:pl  Ten skrypt przywraca przycisk "Pokaż obraz" do wyszukiwarki obrazów Google.
// @description:ja  この UserScript は Google 画像検索結果に「画像を表示」ボタンを追加します。
// @description:ko  이 유저스크립트는 Google 이미지 검색 결과에 ‘이미지 보기’ 버튼을 추가합니다.
// @description:nl  Voegt de "Afbeelding bekijken" knop aan toe aan Google Afbeeldingen.
// @description:sk  Toto rozšírenie pridáva tlačidlo "Zobraziť obrázok" do výsledkov vyhľadávania Google Search.
// @description:tr  Bu betik Google Görseller arama sonuçlarına "Resmi Görüntüle" düğmesini ekler.
// @author          Bae Junehyeon
// @run-at          document-end
// @include         http*://*.google.tld/search*tbm=isch*
// @include         http*://*.google.tld/imgres*
// ==/UserScript==

const lang = {
    ar: 'عرض الصورة',
    cs: 'Zobrazit obrázek',
    da: 'Vis billede',
    de: 'Bild ansehen',
    en: 'View image',
    es: 'Ver imagen',
    fi: 'Näytä kuva',
    fr: 'Voir l\'image',
    he: 'הצג תמונה',  // also 'iw'
    hu: 'Kép megtekintése',
    it: 'Apri immagine',
    iw: 'הצג תמונה',  // same as 'he'
    ja: '画像を表示',
    ko: '이미지 보기',
    lt: 'Rodyti vaizdą',
    nl: 'Afbeelding bekijken',
    no: 'Se bilde',
    pl: 'Pokaż obraz',
    pt: 'Ver imagem',
    ru: 'Показать в полном размере',
    se: 'Visa bild',  // also 'sv'
    sk: 'Zobraziť obrázok',
    sl: 'Ogled slike',
    sv: 'Visa bild',  // same as 'se'
    tr: 'Resmi Görüntüle',
    uk: 'Показати зображення',
    zh: '查看原图',
    'zh-CN': '查看原图',  // also 'zh'
    },
  srch = {
    cs: 'Vyhledat podle obrázku',
    da: 'Søg efter billede',
    de: 'Zur "Bildersuche"',
    en: 'Search by image',
    es: 'Buscar por imagen',
    fr: 'Recherche par image',
    he: 'חפש לפי תמונה',  // also 'iw'
    hu: 'Keresés kép alapján',
    it: 'Ricerca tramite immagine',
    iw: 'חפש לפי תמונה',  // same as 'he'
    ja: '画像を検索',
    ko: '이미지로 검색',
    nl: 'Afbeelding zoeken',
    no: 'Søk med bilde',
    pl: 'Wyszukiwanie obrazem',
    pt: 'Pesquisar por imagem',
    ru: 'Поиск по картинке',
    se: 'Fler storlekar',  // also 'sv'
    sk: 'Vyhľadať podľa obrázku',
    sl: 'Iskanje s sliko',
    sv: 'Fler storlekar',  // same as 'se'
    tr: 'Görselle Ara',
    zh: '以图搜图',
    };

const pgL=document.documentElement.lang;
const localizedViewImage = lang[pgL] || lang[pgL.split('-')[0]] || lang[navigator.language] || lang[navigator.language.split('-')[0]] || lang['en'];
const SBItxt = srch[pgL] || srch[pgL.split('-')[0]] || srch[navigator.language] || srch[navigator.language.split('-')[0]] || srch['en'];

var Btn_1, Btn_2;
var RE=new RegExp('^(?:'+location.origin+')?\/imgres[\?&]imgurl=([^&]*)');

var dataN;
document.querySelectorAll('script').forEach((s)=>{
  let c=s.innerText;
  if (c.startsWith('AF_initDataCallback') && c.length>100) {
    dataN=s;
    }
  })

function addButton(node) {
  if (node.nodeType === Node.ELEMENT_NODE) {
    if (node.classList.contains('irc_ris') || node.classList.contains('Y6heUd') || node.classList.contains('BfYA2c') || node.classList.contains('irc_mi')) {
      let container;
      if (node.classList.contains('Y6heUd') || node.classList.contains('BfYA2c')) container = node;
      else container = node.closest('.irc_c');

      let inView = container.parentNode.style.display !== "none";

      let similarImages = node.querySelectorAll('.rg_l');

      if (!similarImages.length) {
        let block = container.querySelector('div[jsname="ofUehf"]');
        if (block) block.addEventListener('click', function(ev){
          if (ev.target.classList.contains('rg_i')) updateLinkAfterClickOnSimilar(ev);
          });
        }

      [].forEach.call(similarImages, (image) => {
        image.addEventListener('click', updateLinkAfterClickOnSimilar);
      });


      let data=dataN.innerText.replace(/^AF_initDataCallback\((.*)\);$/s,"$1");
      
      let findSrc, focus, tbnID, t;
      try{
        findSrc=((t=container.querySelector(':scope .irc_t .irc_mi, :scope .n3VNCb, :scope .r48jcc')) && t.src) || ((t=container.querySelector(':scope .irc_t .irc_mut')) && t.src);

        focus=document.querySelector('.irc-s');
        if (!focus) {
          tbnID=container.parentNode.dataset['tbnid'];
          if (tbnID) focus=document.querySelector('div[data-tbnid="'+tbnID+'"]');
          }
        if (badImg(findSrc) && focus) {
          for (let k of focus.querySelectorAll('a')) {
            if (RE.test(k.href)) {
              findSrc=unescape(RegExp.$1);
              break;
              }
            }
          }

        if (badImg(findSrc) && dataN) {
          let u= new RegExp('"'+tbnID+'".*?\\[.*?\\[(".*?"),','s').exec(dataN.innerText);
          if (u && u[1]) findSrc=unescape(JSON.parse(u[1]));
          }

      }catch(e){}

if (focus && inView && badImg(findSrc)) {
  obsFocus.observe(focus,{
    childList: false,
    subtree: true,
    attributes: true,
    attributeFilter: [ "href", "src" ]
    });
  }

      let thumbnail = node.querySelector('.irc_rimask.irc_rist');
      let src = bigSrc[findSrc] || findSrc || unescape(thumbnail.querySelector('.rg_l').href.match(/imgurl=([^&]+)/)[1]);

      let buttons = container.querySelector('.irc_but_r tr');
      // new version
      let nv=false;
      if (!buttons) {
        buttons = container.querySelector('.Qc8zh > .irc_ab');
        nv=1;
        }
      if (!buttons) {
        buttons = container.querySelector('.fwCBrd');
        nv=2;
        }
      if (!buttons) {
        buttons = container.querySelector('.kEwVtd, .QCk63e');
        nv=3;
        }
      if (!buttons) {
        buttons = container.querySelector('[jsname="St5Dhe"]');
        nv=4;
        }

      let button = buttons.querySelector(nv? 'a.mgisga' : 'td.mgisga'),
          pn=false;
      if (button === null) {
        let openButton = buttons.querySelector(nv ? (nv >= 3 ? 'a.ZsbmCf, a.J2oL9c, a.jAklOc, a.uZ49bd, a.wvfN0b' : 'a' ) : 'td');

        button = openButton.cloneNode(true);
        if ( (nv == 4) && (openButton.parentNode.childNodes.length == 1) ) {
          openButton=openButton.parentNode;
          button = openButton.cloneNode(true);
          pn=true;
          }
        let sp=button.querySelector(nv ? ( nv >= 3 ? 'div span':'div span:nth-child(2)' ) : 'a span:nth-child(2)');
        if (!sp && (nv == 4)) {
          button.firstChild.firstChild.innerHTML='<span style="margin: 0 10px; color: var(--uv-styles-color-text-emphasis);"></span>';
          sp=button.firstChild.firstChild.firstChild;
          }
        sp.innerText = localizedViewImage;
        sp.style.padding='0';
        // remove icon and style
        try{sp.parentNode.removeChild(sp.previousElementSibling);}catch(e){}
        if (nv==1) sp.className='';

        let link = nv && !pn ? button : button.querySelector('a');
        link.href = src;
        if (!nv) link.className = '';
        link.removeAttribute('data-cthref');
        link.removeAttribute('jsaction');
        link.removeAttribute('data-ved');

        button.classList.remove('irc_lth');
        button.classList.add('mgisga');
        if (nv && button.classList.contains('irc_hol')) button.style='margin-left: 8px;';

        if (nv >= 3) openButton.before(button);
        else openButton.after(button);

        // adding "Search by image"
        let lnks = container.querySelector('.irc_b .irc_hd .irc_dsh');
        let style = 'margin-left:1em', cls = 'o5rIVb SBIlnk dPO1Qe';


        if (!lnks) {
          lnks = (lnks=container.querySelector('.irc_ft, .yKbIbb, .Beeb4e')) && lnks.parentNode;
          cls = cls.replace(/dPO1Qe/,'');
          cls += ' irc_help PvkmDc So4Urb';
          style = '';
          }

        if (lnks) {
          let lnkSBI = document.createElement('a');
          let RE=/.*[\?&](hl=[^&]+)/.exec(location.search); // catch last &hl=xx parameter
          lnkSBI.setAttribute('hrefbase','/searchbyimage?'+(RE?RE[1]+'&':'')+'image_url=');
          lnkSBI.setAttribute('target','_blank');
          lnkSBI.setAttribute('class',cls);
          lnkSBI.setAttribute('style',style);
          lnkSBI.innerText= SBItxt;
          lnks.appendChild(lnkSBI);
          }
      }

      let link = nv ? button : button.querySelector('a');
      link.href = src;
      link = container.querySelector('.SBIlnk');
      link.href = link.attributes.hrefbase.value + encodeURIComponent(src);
      if (inView) {
        Btn_1=button;
        Btn_2=link;
        }
    }
  }
}

function badImg(u) {
  if (!u || u.startsWith('data:') || /^https?:\/\/[^\/]*?\.gstatic\.com\//.test(u)) {
    return true;
    }
}

function updButton(url,src) {
  let u;
  if ( ((u=RE.exec(url)) && (u=u[1])) || (u=src) ) {
    u=unescape(u);
    Btn_1.href=u;
    Btn_2.href=Btn_2.attributes.hrefbase.value + encodeURIComponent(u);
  }
}

var bigSrc={};
function updateLinkAfterClickOnSimilar({target:node}) {
  let src = unescape(node.closest('.rg_l, a').href.match(/imgurl=([^&]+)/)[1]);
  let i = node.src;
  if (i) bigSrc[i]=src;
  let container = node.closest('.irc_c');
  let button = container.querySelector('.mgisga');
  let link = button.querySelector('a');
  if (!link) link = button;
  link.href = src;
  link = container.querySelector('.SBIlnk');
  link.href = link.attributes.hrefbase.value + encodeURIComponent(src);
}

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    const addedNodes = mutation.addedNodes || [];

    [].forEach.call(addedNodes, (newNode) => {
        addButton(newNode);
    });
  });
});

observer.observe(document.body, {
  childList: true,
  subtree: true
});

var obsFocus = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    updButton(mutation.target.href, mutation.target.src);
    });
  });

addButton(document.body);

@Procyon-b Procyon-b changed the title Latest version (1.5.0.17) Latest version (1.5.0.19) Jul 27, 2023
@NightLancer
Copy link

@Procyon-b script seems broken again(checked in FF and Opera), can you update it..?

@kyoyacchi
Copy link

Two new designs for the buttons are currently tested. Here is a new version to handle these cases

// ==UserScript==
// @name            Google Search "View Image" Button
// @name:ru         Google Search кнопка "Показать в полном размере"
// @name:sl         Gumb "Ogled slike" na Google Slikah
// @name:uk         Google Search кнопка "Показати зображення"
// @name:lt         Google paieškos mygtukas "Rodyti vaizdą"
// @name:pl         Przycisk "Pokaż obraz" w wyszukiwarce obrazów Google
// @name:ja         Google 検索「画像を表示」ボタン
// @name:ko         Google 검색 ‘이미지 보기’ 버튼
// @name:nl         Google zoeken "Afbeelding bekijken" knop
// @name:sk         Tlačidlo "Zobraziť obrázok" pre Google Search
// @name:tr         Google Görseller "Resmi Görüntüle" butonu
// @namespace       https://github.com/devunt/make-gis-great-again
// @icon            https://raw.githubusercontent.com/devunt/make-gis-great-again/master/icons/icon.png
// @version         1.5.0.19
// @description     This userscript adds "View Image" button to Google Image Search results.
// @description:ru  Этот скрипт добавляет кнопку "Показать в полном размере" к результатам Google Image Search.
// @description:sl  Ponovno prikaže gumb "Ogled slike" na Google Slikah.
// @description:uk  Цей скрипт додає кнопку "Показати зображення" до результатів Google Image Search.
// @description:lt  Šis vartotojo skriptas prideda mygtuką "Rodyti vaizdą" į Google vaizdo paieškos rezultatus.
// @description:pl  Ten skrypt przywraca przycisk "Pokaż obraz" do wyszukiwarki obrazów Google.
// @description:ja  この UserScript は Google 画像検索結果に「画像を表示」ボタンを追加します。
// @description:ko  이 유저스크립트는 Google 이미지 검색 결과에 ‘이미지 보기’ 버튼을 추가합니다.
// @description:nl  Voegt de "Afbeelding bekijken" knop aan toe aan Google Afbeeldingen.
// @description:sk  Toto rozšírenie pridáva tlačidlo "Zobraziť obrázok" do výsledkov vyhľadávania Google Search.
// @description:tr  Bu betik Google Görseller arama sonuçlarına "Resmi Görüntüle" düğmesini ekler.
// @author          Bae Junehyeon
// @run-at          document-end
// @include         http*://*.google.tld/search*tbm=isch*
// @include         http*://*.google.tld/imgres*
// ==/UserScript==

const lang = {
    ar: 'عرض الصورة',
    cs: 'Zobrazit obrázek',
    da: 'Vis billede',
    de: 'Bild ansehen',
    en: 'View image',
    es: 'Ver imagen',
    fi: 'Näytä kuva',
    fr: 'Voir l\'image',
    he: 'הצג תמונה',  // also 'iw'
    hu: 'Kép megtekintése',
    it: 'Apri immagine',
    iw: 'הצג תמונה',  // same as 'he'
    ja: '画像を表示',
    ko: '이미지 보기',
    lt: 'Rodyti vaizdą',
    nl: 'Afbeelding bekijken',
    no: 'Se bilde',
    pl: 'Pokaż obraz',
    pt: 'Ver imagem',
    ru: 'Показать в полном размере',
    se: 'Visa bild',  // also 'sv'
    sk: 'Zobraziť obrázok',
    sl: 'Ogled slike',
    sv: 'Visa bild',  // same as 'se'
    tr: 'Resmi Görüntüle',
    uk: 'Показати зображення',
    zh: '查看原图',
    'zh-CN': '查看原图',  // also 'zh'
    },
  srch = {
    cs: 'Vyhledat podle obrázku',
    da: 'Søg efter billede',
    de: 'Zur "Bildersuche"',
    en: 'Search by image',
    es: 'Buscar por imagen',
    fr: 'Recherche par image',
    he: 'חפש לפי תמונה',  // also 'iw'
    hu: 'Keresés kép alapján',
    it: 'Ricerca tramite immagine',
    iw: 'חפש לפי תמונה',  // same as 'he'
    ja: '画像を検索',
    ko: '이미지로 검색',
    nl: 'Afbeelding zoeken',
    no: 'Søk med bilde',
    pl: 'Wyszukiwanie obrazem',
    pt: 'Pesquisar por imagem',
    ru: 'Поиск по картинке',
    se: 'Fler storlekar',  // also 'sv'
    sk: 'Vyhľadať podľa obrázku',
    sl: 'Iskanje s sliko',
    sv: 'Fler storlekar',  // same as 'se'
    tr: 'Görselle Ara',
    zh: '以图搜图',
    };

const pgL=document.documentElement.lang;
const localizedViewImage = lang[pgL] || lang[pgL.split('-')[0]] || lang[navigator.language] || lang[navigator.language.split('-')[0]] || lang['en'];
const SBItxt = srch[pgL] || srch[pgL.split('-')[0]] || srch[navigator.language] || srch[navigator.language.split('-')[0]] || srch['en'];

var Btn_1, Btn_2;
var RE=new RegExp('^(?:'+location.origin+')?\/imgres[\?&]imgurl=([^&]*)');

var dataN;
document.querySelectorAll('script').forEach((s)=>{
  let c=s.innerText;
  if (c.startsWith('AF_initDataCallback') && c.length>100) {
    dataN=s;
    }
  })

function addButton(node) {
  if (node.nodeType === Node.ELEMENT_NODE) {
    if (node.classList.contains('irc_ris') || node.classList.contains('Y6heUd') || node.classList.contains('BfYA2c') || node.classList.contains('irc_mi')) {
      let container;
      if (node.classList.contains('Y6heUd') || node.classList.contains('BfYA2c')) container = node;
      else container = node.closest('.irc_c');

      let inView = container.parentNode.style.display !== "none";

      let similarImages = node.querySelectorAll('.rg_l');

      if (!similarImages.length) {
        let block = container.querySelector('div[jsname="ofUehf"]');
        if (block) block.addEventListener('click', function(ev){
          if (ev.target.classList.contains('rg_i')) updateLinkAfterClickOnSimilar(ev);
          });
        }

      [].forEach.call(similarImages, (image) => {
        image.addEventListener('click', updateLinkAfterClickOnSimilar);
      });


      let data=dataN.innerText.replace(/^AF_initDataCallback\((.*)\);$/s,"$1");
      
      let findSrc, focus, tbnID, t;
      try{
        findSrc=((t=container.querySelector(':scope .irc_t .irc_mi, :scope .n3VNCb, :scope .r48jcc')) && t.src) || ((t=container.querySelector(':scope .irc_t .irc_mut')) && t.src);

        focus=document.querySelector('.irc-s');
        if (!focus) {
          tbnID=container.parentNode.dataset['tbnid'];
          if (tbnID) focus=document.querySelector('div[data-tbnid="'+tbnID+'"]');
          }
        if (badImg(findSrc) && focus) {
          for (let k of focus.querySelectorAll('a')) {
            if (RE.test(k.href)) {
              findSrc=unescape(RegExp.$1);
              break;
              }
            }
          }

        if (badImg(findSrc) && dataN) {
          let u= new RegExp('"'+tbnID+'".*?\\[.*?\\[(".*?"),','s').exec(dataN.innerText);
          if (u && u[1]) findSrc=unescape(JSON.parse(u[1]));
          }

      }catch(e){}

if (focus && inView && badImg(findSrc)) {
  obsFocus.observe(focus,{
    childList: false,
    subtree: true,
    attributes: true,
    attributeFilter: [ "href", "src" ]
    });
  }

      let thumbnail = node.querySelector('.irc_rimask.irc_rist');
      let src = bigSrc[findSrc] || findSrc || unescape(thumbnail.querySelector('.rg_l').href.match(/imgurl=([^&]+)/)[1]);

      let buttons = container.querySelector('.irc_but_r tr');
      // new version
      let nv=false;
      if (!buttons) {
        buttons = container.querySelector('.Qc8zh > .irc_ab');
        nv=1;
        }
      if (!buttons) {
        buttons = container.querySelector('.fwCBrd');
        nv=2;
        }
      if (!buttons) {
        buttons = container.querySelector('.kEwVtd, .QCk63e');
        nv=3;
        }
      if (!buttons) {
        buttons = container.querySelector('[jsname="St5Dhe"]');
        nv=4;
        }

      let button = buttons.querySelector(nv? 'a.mgisga' : 'td.mgisga'),
          pn=false;
      if (button === null) {
        let openButton = buttons.querySelector(nv ? (nv >= 3 ? 'a.ZsbmCf, a.J2oL9c, a.jAklOc, a.uZ49bd, a.wvfN0b' : 'a' ) : 'td');

        button = openButton.cloneNode(true);
        if ( (nv == 4) && (openButton.parentNode.childNodes.length == 1) ) {
          openButton=openButton.parentNode;
          button = openButton.cloneNode(true);
          pn=true;
          }
        let sp=button.querySelector(nv ? ( nv >= 3 ? 'div span':'div span:nth-child(2)' ) : 'a span:nth-child(2)');
        if (!sp && (nv == 4)) {
          button.firstChild.firstChild.innerHTML='<span style="margin: 0 10px; color: var(--uv-styles-color-text-emphasis);"></span>';
          sp=button.firstChild.firstChild.firstChild;
          }
        sp.innerText = localizedViewImage;
        sp.style.padding='0';
        // remove icon and style
        try{sp.parentNode.removeChild(sp.previousElementSibling);}catch(e){}
        if (nv==1) sp.className='';

        let link = nv && !pn ? button : button.querySelector('a');
        link.href = src;
        if (!nv) link.className = '';
        link.removeAttribute('data-cthref');
        link.removeAttribute('jsaction');
        link.removeAttribute('data-ved');

        button.classList.remove('irc_lth');
        button.classList.add('mgisga');
        if (nv && button.classList.contains('irc_hol')) button.style='margin-left: 8px;';

        if (nv >= 3) openButton.before(button);
        else openButton.after(button);

        // adding "Search by image"
        let lnks = container.querySelector('.irc_b .irc_hd .irc_dsh');
        let style = 'margin-left:1em', cls = 'o5rIVb SBIlnk dPO1Qe';


        if (!lnks) {
          lnks = (lnks=container.querySelector('.irc_ft, .yKbIbb, .Beeb4e')) && lnks.parentNode;
          cls = cls.replace(/dPO1Qe/,'');
          cls += ' irc_help PvkmDc So4Urb';
          style = '';
          }

        if (lnks) {
          let lnkSBI = document.createElement('a');
          let RE=/.*[\?&](hl=[^&]+)/.exec(location.search); // catch last &hl=xx parameter
          lnkSBI.setAttribute('hrefbase','/searchbyimage?'+(RE?RE[1]+'&':'')+'image_url=');
          lnkSBI.setAttribute('target','_blank');
          lnkSBI.setAttribute('class',cls);
          lnkSBI.setAttribute('style',style);
          lnkSBI.innerText= SBItxt;
          lnks.appendChild(lnkSBI);
          }
      }

      let link = nv ? button : button.querySelector('a');
      link.href = src;
      link = container.querySelector('.SBIlnk');
      link.href = link.attributes.hrefbase.value + encodeURIComponent(src);
      if (inView) {
        Btn_1=button;
        Btn_2=link;
        }
    }
  }
}

function badImg(u) {
  if (!u || u.startsWith('data:') || /^https?:\/\/[^\/]*?\.gstatic\.com\//.test(u)) {
    return true;
    }
}

function updButton(url,src) {
  let u;
  if ( ((u=RE.exec(url)) && (u=u[1])) || (u=src) ) {
    u=unescape(u);
    Btn_1.href=u;
    Btn_2.href=Btn_2.attributes.hrefbase.value + encodeURIComponent(u);
  }
}

var bigSrc={};
function updateLinkAfterClickOnSimilar({target:node}) {
  let src = unescape(node.closest('.rg_l, a').href.match(/imgurl=([^&]+)/)[1]);
  let i = node.src;
  if (i) bigSrc[i]=src;
  let container = node.closest('.irc_c');
  let button = container.querySelector('.mgisga');
  let link = button.querySelector('a');
  if (!link) link = button;
  link.href = src;
  link = container.querySelector('.SBIlnk');
  link.href = link.attributes.hrefbase.value + encodeURIComponent(src);
}

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    const addedNodes = mutation.addedNodes || [];

    [].forEach.call(addedNodes, (newNode) => {
        addButton(newNode);
    });
  });
});

observer.observe(document.body, {
  childList: true,
  subtree: true
});

var obsFocus = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    updButton(mutation.target.href, mutation.target.src);
    });
  });

addButton(document.body);

Can you also make this compatible for mobile version too?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants