import type { EnrichedPlace, Place } from "../types.ts"; import { extractPlaceDetails } from "./search.ts"; const XSSI_PREFIX = ")]}'\n"; const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"; export async function enrichPlace(place: Place): Promise { const query = place.address ? `${place.name} ${place.address}` : place.name; const url = `https://www.google.com/search?tbm=map&hl=en&q=${encodeURIComponent(query)}`; const response = await fetch(url, { headers: { "User-Agent": USER_AGENT }, }); if (!response.ok) { return fallback(place); } const text = await response.text(); const json = text.startsWith(XSSI_PREFIX) ? text.slice(XSSI_PREFIX.length) : text; try { const data: unknown = JSON.parse(json); const details = extractPlaceDetails(data); if (details && isCoordinateMatch(place, details.lat, details.lng)) { return { ...place, rating: details.rating, categories: details.categories, phone: details.phone, website: details.website, hours: details.hours, placeId: details.placeId, mapsUrl: buildMapsUrl(place), }; } } catch { // Fall through to return un-enriched place } return fallback(place); } export async function* enrichPlaces( places: Place[], delayMs: number, ): AsyncGenerator { for (let i = 0; i < places.length; i++) { const place = places[i]; if (!place) continue; yield await enrichPlace(place); if (i < places.length - 1 && delayMs > 0) { await sleep(delayMs); } } } function fallback(place: Place): EnrichedPlace { return { ...place, rating: null, categories: [], phone: null, website: null, hours: null, placeId: null, mapsUrl: buildMapsUrl(place), }; } function isCoordinateMatch( place: Place, lat: number | null, lng: number | null, ): boolean { if (lat === null || lng === null) return false; const tolerance = 0.005; return ( Math.abs(place.lat - lat) < tolerance && Math.abs(place.lng - lng) < tolerance ); } function buildMapsUrl(place: Place): string { return `https://www.google.com/maps/search/?api=1&query=${place.lat},${place.lng}`; } function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); }