Greasy Fork 支持简体中文。

Google Images Direct Link

Add direct links to the picture to the Google Image Search results.

  1. // ==UserScript==
  2. // @name Google Images Direct Link
  3. // @version 1.0.1
  4. // @description Add direct links to the picture to the Google Image Search results.
  5. // @include /^https?:\/\/(www\.)?google\.[a-z\.]{2,5}\/search.*tbm=isch.*/
  6. // @include /^https?:\/\/(www\.)?google\.[a-z\.]{2,5}\/search.*udm=2.*/
  7. // @run-at document-end
  8.  
  9. // @grant GM_openInTab
  10.  
  11. // @copyright 2024, MSerj
  12. // @license MIT
  13. // @namespace https://greasyfork.org/en/users/1321619-mserj
  14. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAuCAMAAACLUGAGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACNUExURXl5eYKCggAAABMTEwAQHgBXnAAKEQAVKAB00AANFwF00Ie75rrX7TSP2At50b7Z7vf390eZ2wd30a3Q6zeR2UaZ2zCN2Ovx9TOP2Ojv9b/Z7qfM6sLb7wx60QR20KvP6zKO2MDa7hqC1CyL1+bt9Mfd7w970h2D1Mbd75/J6QJ10Hq05AALEwA6aQAHDC3GXGkAAAAJcEhZcwAADsIAAA7CARUoSoAAAAC8SURBVEhL7c9HE4IwEIbhYI3YYsMOKvb2/3+eYYkHyS5sDg4X3lsyz3yTCJc8UXOo7qwbTV4t0G3Jq1Npq5K03+2l9c1F/vZgqKCRORe8ZDxx0XIKemZOBTqYg+ZtL5ZKrdbM7UDjzTaMWNspljKMGHqn8V5jzQ9wkUTp7/JvhMYxoQmMawqjOqYwpuMjhRGd4BOObQ34bA7Zsvqi8ZXClvZv9DLykvuDxsgv86q03f/188XrDZqfq3ZIeB9W/0N6iNgAzAAAAABJRU5ErkJggg==
  15. // ==/UserScript==
  16.  
  17. /* globals trustedTypes */
  18. /* jshint esversion: 11 */
  19.  
  20. function setClasses() {
  21. document.body.classList.remove('nocrop')
  22. document.body.classList.add('nocropHover', 'noRadius')
  23. }
  24.  
  25. // Custom TrustedTypes handling: Google's policies are giving us trouble in some configs.
  26. let needsTrustedHTML = false
  27. const passThroughFunc = string => string
  28. const TTPName = 'toast'
  29. let TP = { createHTML: passThroughFunc, createScript: passThroughFunc, createScriptURL: passThroughFunc }
  30. try {
  31. if (window.isSecureContext && window.trustedTypes?.createPolicy) {
  32. TP = trustedTypes.defaultPolicy || window.trustedTypes.createPolicy(TTPName, TP)
  33. needsTrustedHTML = true
  34. }
  35. } catch (e) {
  36. console.error(e)
  37. }
  38.  
  39. function updatePage() {
  40. if (!document.querySelector('#directLinkStyles')) {
  41. let styleElement = document.createElement('style')
  42. styleElement.id = 'directLinkStyles'
  43. styleElement.innerHTML = trustedHTML(`
  44. .linkToTarget {
  45. position: absolute;
  46. right: 0;
  47. top: 0;
  48. opacity: 0;
  49. background-color: rgba(255, 255, 255, 0.5);
  50. transition: background-color 0.5s, opacity 0.5s;
  51. box-shadow: 3px 5px 10px rgba(0, 0, 0, 0.5);
  52. }
  53. .failed .linkToTargetlink {
  54. color: rgba(230, 100, 100) !important;
  55. }
  56. a:hover .linkToTarget {
  57. opacity: 0.6;
  58. }
  59. a:hover .linkToTarget:hover {
  60. opacity: 1;
  61. }
  62. .linksdone:hover .linkToTarget {
  63. cursor: pointer;
  64. }
  65. .linkToTargetLink {
  66. color: rgba(155, 177, 233, 1) !important;
  67. font-size: 22pt;
  68. display: block;
  69. font-weight: bold;
  70. text-decoration: none !important;
  71. transition: color 0.5s, font-size 0.5s, padding 0.5s;
  72. }
  73. .temp .linkToTargetLink {
  74. color: rgba(200, 200, 200) !important;
  75. }
  76. .linkToTargetLink:hover {
  77. color: rgba(155, 177, 233, 1) !important;
  78. padding: 8px;
  79. font-size: 30pt;
  80. }
  81. body.nocropHover div#islmp div#islrg div.islrc div.isv-r a.islib:hover,
  82. body.nocropHover a .F0uyec:hover,
  83. body.nocropHover a:hover img,
  84. body.nocropHover .mNsIhb .YQ4gaf:hover,
  85. body.nocropHover .H8Rx8c img:hover {
  86. overflow: visible;
  87. z-index: 100;
  88. object-fit: contain;
  89. }
  90. body.noRadius a .F0uyec,
  91. body.noRadius div .eA0Zlc.mkpRId,
  92. body.noRadius div .cC9Rib {
  93. border-radius: 0;
  94. }
  95. </style>`)
  96.  
  97. document.head.appendChild(styleElement)
  98. }
  99. document
  100. .querySelectorAll(
  101. `.rg_di.rg_bx a.rg_l img:not(.linksdone),
  102. #islrg div.isv-r a.wXeWr.islib img:not(.linksdone),
  103. div#res div#rso h3 a g-img img:not(.linksdone),
  104. div#islmp div.islrc a[role="button"] img:not(.linksdone)
  105. `
  106. )
  107. .forEach(function (img) {
  108. if (img.classList.contains('linksdone'))
  109. // Why is the selector not working??
  110. return
  111. const linkDiv = document.createElement('div')
  112. linkDiv.className = 'linkToTarget'
  113. linkDiv.innerHTML = trustedHTML("<a class='linkToTargetLink'>↗️</a>")
  114. img.parentElement.appendChild(linkDiv)
  115. linkDiv.querySelector('a.linkToTargetLink').onclick = clickLink
  116. img.classList.add('linksdone')
  117. })
  118. }
  119.  
  120. function clickLink(e) {
  121. e.stopPropagation()
  122. e.preventDefault()
  123.  
  124. waitForLink(e.target, e)
  125. return false
  126. }
  127.  
  128. function waitForLink(target, event) {
  129. const linkParent = target.parentElement.closest('a')
  130. const imgUrlStartIndex = linkParent.href.indexOf('imgurl=')
  131.  
  132. const openInNew = event.ctrlKey
  133.  
  134. if (imgUrlStartIndex < 0) {
  135. const $e = linkParent
  136. const resTries = linkParent.getAttribute('resTries') ? linkParent.getAttribute('resTries') * 1 + 1 : 1
  137. if (resTries === 1) {
  138. $e.click()
  139. linkParent.querySelector('img').click()
  140. setTimeout(function () {
  141. $e.click()
  142. }, 200)
  143. }
  144.  
  145. linkParent.setAttribute('resTries', resTries)
  146.  
  147. if (linkParent.getAttribute('resTries') * 1 >= 100) {
  148. linkParent.classList.add('linksdone')
  149. linkParent.classList.add('failed')
  150. linkParent.querySelector('.linkToTarget span').innerHTML = TP.createHTML('x')
  151. return true
  152. }
  153.  
  154. if (!linkParent.classList.contains('linkswait')) {
  155. linkParent.classList.add('linkswait')
  156. linkParent.querySelector('.linkToTarget').classList.add('temp')
  157. linkParent.querySelector('.linkToTarget span').innerHTML = TP.createHTML('...')
  158. }
  159. setTimeout(function () {
  160. waitForLink(target, event)
  161. }, 200)
  162.  
  163. return true
  164. } else {
  165. let picLink = decodeURIComponent(linkParent.href.slice(imgUrlStartIndex + 7).split('&')[0])
  166. linkParent.classList.remove('linkswait')
  167. const linkToTarget = linkParent.querySelector('.linkToTarget')
  168. if (linkToTarget) {
  169. linkToTarget.classList.remove('temp')
  170. linkToTarget.querySelector('a.linkToTargetLink').href = picLink
  171. }
  172. linkParent.classList.add('linksdone')
  173.  
  174. if (event.which === 3) return false
  175. if (openInNew) {
  176. GM_openInTab(picLink, { active: true, insert: true, parent: true })
  177. } else {
  178. location.href = picLink
  179. }
  180. }
  181. }
  182.  
  183. function trustedHTML(string) {
  184. if (!needsTrustedHTML) return string
  185. return TP.createHTML(string)
  186. }
  187.  
  188. setClasses()
  189. updatePage()
  190. setInterval(updatePage, 1000)