mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 18:52:56 +00:00
upload
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Utility functions to parse map URLs from various sources
|
||||
* Supports: mapy.cz, Google Maps
|
||||
*/
|
||||
|
||||
export interface MapCoordinates {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
zoom?: number;
|
||||
address?: string;
|
||||
source: 'mapy.cz' | 'google-maps' | 'unknown';
|
||||
// Detailed address components from reverse geocoding
|
||||
street?: string;
|
||||
city?: string;
|
||||
zip?: string;
|
||||
country?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse mapy.cz URL
|
||||
* Example: mapy.cz/en/letecka?q=krnov%20stadion&source=firm&id=12954454&ds=2&x=17.6996859&y=50.0947150&z=19
|
||||
*/
|
||||
export function parseMapyCzUrl(url: string): MapCoordinates | null {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
// Check if it's a mapy.cz domain
|
||||
if (!urlObj.hostname.includes('mapy.cz') && !urlObj.hostname.includes('mapy.com')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const params = urlObj.searchParams;
|
||||
const xParam = params.get('x');
|
||||
const yParam = params.get('y');
|
||||
const zParam = params.get('z');
|
||||
const qParam = params.get('q');
|
||||
|
||||
if (xParam && yParam) {
|
||||
const longitude = parseFloat(xParam);
|
||||
const latitude = parseFloat(yParam);
|
||||
const zoom = zParam ? parseInt(zParam) : undefined;
|
||||
|
||||
if (isNaN(latitude) || isNaN(longitude)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
latitude,
|
||||
longitude,
|
||||
zoom,
|
||||
address: qParam ? decodeURIComponent(qParam) : undefined,
|
||||
source: 'mapy.cz',
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Error parsing mapy.cz URL:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Google Maps URL
|
||||
* Supports various formats:
|
||||
* - /maps/place/.../@lat,lng,zoom
|
||||
* - /maps?q=lat,lng
|
||||
* - /maps/@lat,lng,zoom
|
||||
*/
|
||||
export function parseGoogleMapsUrl(url: string): MapCoordinates | null {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
|
||||
// Check if it's a Google Maps domain
|
||||
if (!urlObj.hostname.includes('google.com')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to extract from pathname (/@lat,lng,zoom format)
|
||||
const pathMatch = urlObj.pathname.match(/@(-?\d+\.\d+),(-?\d+\.\d+),(\d+)z/);
|
||||
if (pathMatch) {
|
||||
const latitude = parseFloat(pathMatch[1]);
|
||||
const longitude = parseFloat(pathMatch[2]);
|
||||
const zoom = parseInt(pathMatch[3]);
|
||||
|
||||
if (!isNaN(latitude) && !isNaN(longitude)) {
|
||||
// Try to extract place name from pathname
|
||||
const placeMatch = urlObj.pathname.match(/\/place\/([^/]+)/);
|
||||
const address = placeMatch ? decodeURIComponent(placeMatch[1].replace(/\+/g, ' ')) : undefined;
|
||||
|
||||
return {
|
||||
latitude,
|
||||
longitude,
|
||||
zoom: !isNaN(zoom) ? zoom : undefined,
|
||||
address,
|
||||
source: 'google-maps',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Try to extract from query parameters
|
||||
const params = urlObj.searchParams;
|
||||
const qParam = params.get('q');
|
||||
|
||||
if (qParam) {
|
||||
// Check if q parameter contains coordinates (lat,lng format)
|
||||
const coordMatch = qParam.match(/(-?\d+\.\d+),(-?\d+\.\d+)/);
|
||||
if (coordMatch) {
|
||||
const latitude = parseFloat(coordMatch[1]);
|
||||
const longitude = parseFloat(coordMatch[2]);
|
||||
|
||||
if (!isNaN(latitude) && !isNaN(longitude)) {
|
||||
return {
|
||||
latitude,
|
||||
longitude,
|
||||
address: qParam.includes(',') ? undefined : qParam,
|
||||
source: 'google-maps',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try data parameter (some Google Maps links use this)
|
||||
const dataMatch = urlObj.pathname.match(/!3d(-?\d+\.\d+)!4d(-?\d+\.\d+)/);
|
||||
if (dataMatch) {
|
||||
const latitude = parseFloat(dataMatch[1]);
|
||||
const longitude = parseFloat(dataMatch[2]);
|
||||
|
||||
if (!isNaN(latitude) && !isNaN(longitude)) {
|
||||
return {
|
||||
latitude,
|
||||
longitude,
|
||||
source: 'google-maps',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Error parsing Google Maps URL:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function to parse any supported map URL
|
||||
*/
|
||||
export function parseMapUrl(url: string): MapCoordinates | null {
|
||||
if (!url || typeof url !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Normalize the URL (add protocol if missing)
|
||||
let normalizedUrl = url.trim();
|
||||
if (!normalizedUrl.startsWith('http://') && !normalizedUrl.startsWith('https://')) {
|
||||
normalizedUrl = 'https://' + normalizedUrl;
|
||||
}
|
||||
|
||||
// Try parsing as mapy.cz
|
||||
const mapyCzResult = parseMapyCzUrl(normalizedUrl);
|
||||
if (mapyCzResult) {
|
||||
return mapyCzResult;
|
||||
}
|
||||
|
||||
// Try parsing as Google Maps
|
||||
const googleMapsResult = parseGoogleMapsUrl(normalizedUrl);
|
||||
if (googleMapsResult) {
|
||||
return googleMapsResult;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate if coordinates are within valid ranges
|
||||
*/
|
||||
export function validateCoordinates(lat: number, lng: number): boolean {
|
||||
return (
|
||||
!isNaN(lat) &&
|
||||
!isNaN(lng) &&
|
||||
lat >= -90 &&
|
||||
lat <= 90 &&
|
||||
lng >= -180 &&
|
||||
lng <= 180
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse geocode coordinates to get detailed address information
|
||||
* Uses Nominatim API (OpenStreetMap)
|
||||
*/
|
||||
export async function reverseGeocode(lat: number, lng: number): Promise<Partial<MapCoordinates>> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&addressdetails=1&accept-language=cs`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'FotbalClub/1.0',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Reverse geocoding failed');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const addr = data.address || {};
|
||||
|
||||
return {
|
||||
address: data.display_name,
|
||||
street: addr.road || addr.street || addr.pedestrian || addr.footway,
|
||||
city: addr.city || addr.town || addr.village || addr.municipality,
|
||||
zip: addr.postcode,
|
||||
country: addr.country || 'Česká republika',
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Reverse geocoding error:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user