acoolrocket

Google Lens Plus v1.1

Nov 17th, 2025 (edited)
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.51 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Google Lens Plus
  3. // @version 1.1
  4. // @description Scroll to the bottom of the page [disabled], waits for the page to fully load, extract and arrange unique resolutions,
  5. // @description and display them in a column on the right side of the page with tap-to-copy and auto-scroll functionality.
  6. // @author LF2005
  7. // @license MIT
  8. // @match https://www.google.com/search?*
  9. // @grant GM_setClipboard
  10. // @namespace https://greasyfork.org/users/731843 and Acoolrocket with help from ChatGPT
  11. // @downloadURL https://update.greasyfork.org/scripts/533357/Google%20Lens%20Plus.user.js
  12. // @updateURL https://update.greasyfork.org/scripts/533357/Google%20Lens%20Plus.meta.js
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // Function to verify the correct page structure
  19. function verifyPageStructure() {
  20. // Check if the div with id="rso" exists
  21. const rsoDiv = document.getElementById('rso');
  22. if (!rsoDiv) {
  23. console.log('No div with id="rso" found. Exiting script.');
  24. return false;
  25. }
  26.  
  27. // Check if the rso div contains divs with class "ULSxyf"
  28. const ulsxyfDivs = rsoDiv.querySelectorAll('div.ULSxyf');
  29. if (ulsxyfDivs.length === 0) {
  30. console.log('No divs with class "ULSxyf" found inside rso. Exiting script.');
  31. return false;
  32. }
  33.  
  34. return true;
  35. }
  36.  
  37. // Function to scroll to the bottom of the page and detect when no new content is loaded
  38. function scrollToBottom() {
  39. return new Promise((resolve) => {
  40. let previousHeight = document.body.offsetHeight;
  41. let attempts = 0;
  42. const maxAttempts = 40; // Maximum attempts to scroll before giving up
  43.  
  44. const scrollInterval = setInterval(() => {
  45. window.scrollBy(0, window.innerHeight * 2); // Scroll down by two viewport heights
  46. const newHeight = document.body.offsetHeight;
  47.  
  48. // Check if the page height has changed
  49. if (newHeight === previousHeight) {
  50. attempts++;
  51. if (attempts >= maxAttempts) {
  52. clearInterval(scrollInterval); // Stop scrolling if no new content is loaded after max attempts
  53. resolve();
  54. }
  55. } else {
  56. attempts = 0; // Reset attempts if new content is loaded
  57. }
  58.  
  59. previousHeight = newHeight; // Update the previous height
  60.  
  61. // Stop scrolling if we're at the bottom
  62. if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
  63. clearInterval(scrollInterval);
  64. resolve();
  65. }
  66. }, 300); // Adjust the interval (in milliseconds) for faster scrolling
  67. });
  68. }
  69.  
  70. // Function to extract unique resolutions
  71. function isResolution(text) {
  72. // Must match e.g. 200x300 or 1,920x1,080
  73. const resolutionPattern = /^\d{2,5}(?:,\d{3})?x\d{2,5}(?:,\d{3})?$/;
  74. return resolutionPattern.test(text);
  75. }
  76.  
  77. function isCurrency(text) {
  78. // Common currency patterns: $10.99, USD 10.99, €10, etc.
  79. const currencyPattern = /[\$\€\£]\s*\d+([.,]\d{2})?|USD|EUR|CAD|GBP/;
  80. return currencyPattern.test(text);
  81. }
  82.  
  83. function extractResolutions() {
  84. const outerSpans = document.querySelectorAll('span.cyspcb.DH9lqb.VBZLA');
  85. const resolutions = new Set();
  86. outerSpans.forEach(outerSpan => {
  87. const innerSpan = outerSpan.querySelector('span');
  88. if (
  89. innerSpan &&
  90. !innerSpan.innerHTML.endsWith('ago') &&
  91. isResolution(innerSpan.innerHTML.replace(/,/g, '').trim()) && // only accept resolution
  92. !isCurrency(innerSpan.innerHTML)
  93. ) {
  94. resolutions.add(innerSpan.innerHTML);
  95. }
  96. });
  97. return Array.from(resolutions);
  98. }
  99.  
  100. // Function to sort resolutions by size (from largest to smallest)
  101. function sortResolutions(resolutions) {
  102. return resolutions.sort((a, b) => {
  103. // Remove commas temporarily for comparison
  104. const [aWidth, aHeight] = a.replace(/,/g, '').split('x').map(Number);
  105. const [bWidth, bHeight] = b.replace(/,/g, '').split('x').map(Number);
  106. const aArea = aWidth * aHeight;
  107. const bArea = bWidth * bHeight;
  108. return bArea - aArea; // Sort in descending order
  109. });
  110. }
  111.  
  112. // Function to copy text to clipboard using the Clipboard API
  113. async function copyToClipboard(text) {
  114. try {
  115. await navigator.clipboard.writeText(text);
  116. console.log('Copied to clipboard:', text);
  117. return true;
  118. } catch (err) {
  119. console.error('Failed to copy:', err);
  120. return false;
  121. }
  122. }
  123.  
  124. // Function to inject the results into a column on the right side of the page
  125. function injectResultsColumn(resolutions) {
  126. const column = document.createElement('div');
  127. column.id = 'resolutions-column';
  128. column.style.position = 'fixed';
  129. column.style.top = '0';
  130. column.style.right = '0';
  131. column.style.width = '100px';
  132. column.style.height = '100vh';
  133. column.style.backgroundColor = 'black';
  134. column.style.boxShadow = '-2px 0 5px rgba(0, 0, 0, 0.1)';
  135. column.style.padding = '20px';
  136. column.style.overflowY = 'auto';
  137. column.style.zIndex = '1000';
  138.  
  139. const title = document.createElement('h1');
  140. title.textContent = 'Resolutions';
  141. title.style.marginTop = '0';
  142. column.appendChild(title);
  143.  
  144. resolutions.forEach(resolution => {
  145. const resolutionElement = document.createElement('div');
  146. resolutionElement.textContent = resolution;
  147. resolutionElement.style.marginBottom = '1px';
  148. resolutionElement.style.cursor = 'pointer';
  149. resolutionElement.style.padding = '1px';
  150. resolutionElement.style.borderRadius = '1px';
  151. resolutionElement.style.backgroundColor = '#000000';
  152. resolutionElement.style.transition = 'background-color 0.2s';
  153.  
  154. resolutionElement.addEventListener('mouseenter', () => {
  155. resolutionElement.style.backgroundColor = '#0a0359';
  156. });
  157. resolutionElement.addEventListener('mouseleave', () => {
  158. resolutionElement.style.backgroundColor = '#000000';
  159. });
  160.  
  161. resolutionElement.addEventListener('click', async () => {
  162. // Find the matching result and scroll to it
  163. const xpath = `//*[contains(text(), "${resolution}")]`;
  164. const nodes = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  165. if (nodes.snapshotLength > 0) {
  166. nodes.snapshotItem(0).scrollIntoView({behavior: "auto", block: "center"});
  167. }
  168. // Optionally still copy to clipboard (can keep this or remove)
  169. const success = await copyToClipboard(resolution);
  170. if (success) {
  171. resolutionElement.textContent = 'Copied!';
  172. setTimeout(() => {
  173. resolutionElement.textContent = resolution;
  174. }, 1000);
  175. }
  176. });
  177. column.appendChild(resolutionElement);
  178. });
  179.  
  180. document.body.appendChild(column);
  181. }
  182.  
  183. // Main function
  184. async function main() {
  185. // Verify page structure first
  186. if (!verifyPageStructure()) {
  187. return;
  188. }
  189.  
  190. console.log('Scrolling to the bottom of the page...');
  191. //await scrollToBottom(); // Scroll to the bottom
  192. console.log('Finished scrolling. Extracting resolutions...');
  193.  
  194. const uniqueResolutions = extractResolutions(); // Extract resolutions
  195. console.log('Unique Resolutions (unsorted):', uniqueResolutions);
  196.  
  197. const sortedResolutions = sortResolutions(uniqueResolutions); // Sort resolutions
  198. console.log('Unique Resolutions (sorted):', sortedResolutions);
  199.  
  200. injectResultsColumn(sortedResolutions); // Inject the results into a column
  201. }
  202.  
  203. // Wait for the page to load, then run the main function
  204. window.addEventListener('load', main);
  205. })();
Advertisement
Add Comment
Please, Sign In to add comment