Skip to content

Instantly share code, notes, and snippets.

@fanfare
Last active December 7, 2022 19:31
Show Gist options
  • Save fanfare/1305eb8698021434768bed0ab4883d7b to your computer and use it in GitHub Desktop.
Save fanfare/1305eb8698021434768bed0ab4883d7b to your computer and use it in GitHub Desktop.
get google related images URL ( https://www.google.com/search?tbs=sbi: ... ) based on an image URL
// notes:
// this function should be used from within the background script of a webextension
// also included are two examples at the bottom to demonstrate its use
async function getImageResultsURLFromImageURL(URL) {
// input: string
// the input is the URL of the image you want to search for
// it can either start with "http" or "data:" (for base64 encoded images)
// output: string
// the output is the URL of the image results (regular, not google lens)
// the output URL starts with "https://www.google.com/search?tbs=sbi:"
const lens = async (URL) => {
// find the normal image results URL within the HTML of the Google Lens results
const response = await fetch(URL, {
"body": null,
"method": "GET",
"mode": "cors",
})
let body = await response.text()
let index = body.indexOf(`https://www.google.com/search?tbs`)
if (index === -1) {
throw new Error("tbs prefix url not found")
}
body = body.substring(index, body.length)
index = body.indexOf(`"`)
if (index === -1) {
throw new Error("quotation marks not found")
}
body = body.substring(0,index)
body = body.replace(`\\u003d`, "=")
if (!body.startsWith("https")) {
throw new Error(`body does not start with https, body length is ${body.length}`)
}
return body
}
const get = async (URL) => {
// find the Google Lens results URL from an HTTP/HTTPS image URL
const encodedURL = encodeURIComponent(URL)
const crawlRequestURL = `https://lens.google.com/uploadbyurl?url=${encodedURL}&hl=en&re=df&st=${+ new Date()}&ep=gisbubu`
const response = await fetch(crawlRequestURL, {
"body": null,
"method": "GET",
"mode": "cors",
})
return response.url
}
const post = async (URL) => {
// find the Google Lens results URL from a base64 image URL
const blob = await (await fetch(URL)).blob()
const formData = new FormData()
formData.append("encoded_image", blob, `${+ new Date()}.png`)
let response = await fetch(`https://lens.google.com/upload?hl=en&re=df&st=${+ new Date()}&ep=gisbubb`, {
"body": formData,
"method": "POST",
"mode": "cors"
})
let text = await response.text()
if (text.indexOf("refresh") === -1) {
throw new Error("no base64 meta refresh found")
return null
}
let index = text.indexOf('https://lens.google.com')
text = text.slice(index)
index = text.indexOf('"')
if (index === -1) {
index = text.indexOf("'")
if (index === -1) {
throw new Error("quotation marks not found")
return null
}
}
text = text.slice(0,index)
if (!text.startsWith("http")) {
throw new Error("url did not start with http")
return null
}
return text
}
try {
// if no valid URL provided, return null
if (!URL || URL.length === 0 || typeof URL !== "string") {
return null
}
let redirect = null
if (URL.startsWith("data:")) {
// get the Google Lens URL based on a base64 image URL
redirect = await post(URL)
}
else {
// get the Google Lens URL based on an HTTP/HTTPS image URL
redirect = await get(URL)
}
// return the normal image results URL
return await lens(redirect)
}
catch(e) {
console.error(e)
if (!URL.startsWith("data:")) {
// as a fallback, return the Google Lens results URL
const encodedURL = URL.replaceAll("?", '%3F').replaceAll("&", '%26')
return `https://lens.google.com/uploadbyurl?url=${encodedURL}`
}
else {
// return null if a base64 image was provided and wasn't able to resolve
return null
}
}
};
// examples:
// get the normal image results URL from an HTTPS image URL
(async function() {
const imageURL = "https://i.imgur.com/VcMUWBC.jpeg"
const results = await getImageResultsURLFromImageURL(imageURL)
console.log(results) // https://www.google.com/search?tbs=sbi:AMhZZisKeirUN5_1-_1AfP0ZUcMShmlwPs0MGTCsOcPrfqv_1ii1AY2ximpsNpO6TnEsNDa8L5Bc0hKxRecsm8wEJfgFG1K85SBAGW-K3bb0sVPuImQHW24qIIU7xfzRpHFgKl2REAScR2RGphYZDWf_1dBxVNefRmZ2GQ
})();
// get the normal image results URL from a base64 image URL
(async function() {
const imageURL = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzf/wAARCAA3AEADASIAAhEBAxEB/8QAGwAAAQUBAQAAAAAAAAAAAAAAAwABAgQGBQf/xAAuEAABAwMDAwMDAwUAAAAAAAABAgMRAAQhBRIxBkFRE2GRInGBBxUjQrHBwvH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A3u2BkVBSRNHXxxQinufigGpM8CkEfaalkU6YJoIhvBEjzVttsgZpkISck0YEJQIoGSIoVyqBTrUQJFVHVFVBegETzQHOTIqCn9oMngE1Ru9XtrZj1XlFKZAHuT2oLiqGCArmq5v2yQPUSCUBwJnO08Ggm9QraUuJIVxnmg6gdAwap6zqZ0/S7i7QkKLQBgmJyB/mgrW4kwsKB8RWX/US6eY6aWlKlILr6EScEQd3+poNJpeuo1AlsgpdCd57CCTA+Iq+pxPIIzXkXSXUbyNfs7Iytl1JSpRA/jMKxMeYrR9U9WuaS+1b2RaW5G971ASAOwwee/x5oCtalqPqKW9cBSFgBaV7SFQIyAnv3oGqajYXG4XTyUoUZLTaglM+Y5rzA3jzuXHHHPdajFSFyEwScc/SIn80G/vepkOLQbZl10oSEhSzCIE/MzmuVc9UagXVlHopMlZVtnNZNd6oz/SIzmhquCRHCfPn8UGuV1rrjLywm5acTG36mhH3Heff2rja71JfaslAvblBbQorS2luADBAgknyfmuM/cGRCjCgJk81VU7uOc0He03qH9ouGLmwU2l1pxKzKNwVBGCPBgfFB1zX3db1S71G4DaXrggrDSNqcJCRjMYArjExGMeB3qTTqmd3p7khRE/VzH/aBw4R3n3PYU3qc5JHmaVKgip2B/ao7lFEnv3pUqBE7m442nAqA7mceaVKgtIKQjByJ4FV1ncQASSPNKlQf//Z"
const results = await getImageResultsURLFromImageURL(imageURL)
console.log(results) // https://www.google.com/search?tbs=sbi:AMhZZiuQRfow5gK0DKoShC5tjLNXDbIsFPMtCfNpUGU2NtsYLLbRE16ITRsECSMmZC8I1HmU04Cgi0--0qUci_14tkoOZAg2gisCcAOceGfFNypdlC0W5SP9hhW7qwbq-OSkd-ts49B6k5KLXfFZTC5KOsrBJiRs3HA
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment