Skip to content

Instantly share code, notes, and snippets.

@Lissy93
Last active February 27, 2024 00:44
Show Gist options
  • Save Lissy93/444a1dcf8bb6763a8ab9da8451544321 to your computer and use it in GitHub Desktop.
Save Lissy93/444a1dcf8bb6763a8ab9da8451544321 to your computer and use it in GitHub Desktop.
API for UK food product photos (via Cloudflare Workers)
/**
* Cloudflare Worker script for displaying UK food products
* Fetches given item from Tesco.com using search endpoint
* Optionally resizes to specified dimensions
* Implements caches recently requested images
* Swaers a little bit when an error happens
*/
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request, event))
})
const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36';
const TESCO_SEARCH_URL = 'https://www.tesco.com/groceries/en-GB/search?query=';
const WELCOME = 'Welcome to the Snack Champion\'s product photo API! 🥤🍬🍿😋\n' +
'To use this service, please specify a product name and optional dimensions.';
async function handleRequest(request, event) {
const cacheUrl = new URL(request.url);
const cacheKey = new Request(cacheUrl.toString(), request);
const cache = caches.default;
// Check if the response is already in the cache
let response = await cache.match(cacheKey);
if (response) {
return response; // Return the cached response if it exists
}
try {
const { productName, dimension } = extractProductAndDimension(request.url);
if (!productName) {
return new Response(WELCOME, { status: 418 });
}
const imageURL = await fetchProductImageURL(productName, dimension);
if (imageURL) {
response = await fetchAndReturnImage(imageURL);
// Store the fetched response in the cache.
event.waitUntil(cache.put(cacheKey, response.clone()));
return response;
} else {
return new Response("Image not found. Fuck sake", { status: 404 });
}
} catch (error) {
console.error(error); // Log the error for debugging
return new Response("An error occurred. Shit", { status: 500 });
}
}
function extractProductAndDimension(url) {
const pathSegments = new URL(url).pathname.split("/").filter(Boolean);
return {
productName: pathSegments[0],
dimension: pathSegments[1] // undefined if not present
};
}
async function fetchProductImageURL(product, dimension) {
const response = await fetch(`${TESCO_SEARCH_URL}${product}`, { headers: { 'User-Agent': USER_AGENT } });
const body = await response.text();
const match = body.match(/(https:\/\/digitalcontent\.api\.tesco\.com\/v2\/media\/[^?]+)/);
if (match) {
let imageURL = match[0];
if (dimension) {
imageURL += `?h=${dimension}&w=${dimension}`;
}
return imageURL;
} else {
return null;
}
}
async function fetchAndReturnImage(imageURL) {
const response = await fetch(imageURL);
const imageBlob = await response.blob();
return new Response(imageBlob, {
headers: { 'Content-Type': response.headers.get('Content-Type') }
});
}
@Lissy93
Copy link
Author

Lissy93 commented Feb 27, 2024

I made this in order to get product photos for github.com/lissy93/cso.
Here's a screenshot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment