fix(maps): resolve google place links to the place pin instead of the camera

A Google place URL carries two points: @lat,lng is the centre of the map
view, the !3d!4d data param is the place itself. extractCoords took the
camera first, so a pasted share link put the place around 170 m off and
reverse geocoded the wrong street. The data param is now read before @;
the order of @ and ?q=/?ll= is unchanged. REST and the resolve_maps_url
MCP tool share the resolver, so both pick this up.

Refs #2635
This commit is contained in:
Maurice
2026-10-12 09:21:56 +02:00
parent aa1bb41cf5
commit 7397e33c31
2 changed files with 88 additions and 3 deletions
+5 -3
View File
@@ -34,12 +34,14 @@ export type MapsLink =
{ kind: 'resolved'; result: ResolvedMapsUrl } | { kind: 'amap'; lat: number; lng: number; name: string | null };
// Extract coordinates from a string (URL or page body). Google Maps encodes
// them several ways: /@lat,lng,zoom · !3dlat!4dlng (map data param) · ?q=/?ll=.
// them several ways: !3dlat!4dlng (map data param) · /@lat,lng,zoom · ?q=/?ll=.
// The data param is the place itself, while @ is only where the camera looks,
// often a hundred metres off on a place link, so the data param wins (#2635).
function extractCoords(s: string): { lat: number; lng: number } | null {
const at = s.match(/@(-?\d+\.\d+),(-?\d+\.\d+)/);
if (at) return { lat: Number.parseFloat(at[1]), lng: Number.parseFloat(at[2]) };
const data = s.match(/!3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/);
if (data) return { lat: Number.parseFloat(data[1]), lng: Number.parseFloat(data[2]) };
const at = s.match(/@(-?\d+\.\d+),(-?\d+\.\d+)/);
if (at) return { lat: Number.parseFloat(at[1]), lng: Number.parseFloat(at[2]) };
const q = s.match(/[?&](?:q|ll)=(-?\d+\.\d+),(-?\d+\.\d+)/);
if (q) return { lat: Number.parseFloat(q[1]), lng: Number.parseFloat(q[2]) };
return null;