@@ -703,7 +703,7 @@ <h1>Galaxy Instance Map</h1>
703703 const width = 1000 ;
704704 const height = 600 ;
705705
706- // Geolocation cache for servers
706+ // Geolocation cache for servers or city lookups
707707 const GEO_CACHE_KEY = 'galaxyServerGeoCache' ;
708708 const GEO_CACHE_DURATION = 30 * 24 * 60 * 60 * 1000 ; // 30 days
709709
@@ -1042,11 +1042,76 @@ <h1>Galaxy Instance Map</h1>
10421042 city : 'Unknown' ,
10431043 latitude : 39.8283 ,
10441044 longitude : - 98.5795 ,
1045- flag : '🇺� ' ,
1045+ flag : '🇺🇸 ' ,
10461046 countryCode : 'US'
10471047 } ;
10481048 }
10491049
1050+ // Geocode a city name (optionally using region for disambiguation)
1051+ async function geocodeCityName ( city , region = '' , forceRefresh = false ) {
1052+ if ( ! city || city . trim ( ) === '' ) {
1053+ return {
1054+ country : 'Unknown' ,
1055+ city : 'Unknown' ,
1056+ latitude : null ,
1057+ longitude : null ,
1058+ flag : '🏳️'
1059+ } ;
1060+ }
1061+
1062+ const key = `${ city } |${ region } ` . toLowerCase ( ) ;
1063+
1064+ if ( ! forceRefresh ) {
1065+ const cached = getGeoFromCache ( key ) ;
1066+ if ( cached ) {
1067+ return cached ;
1068+ }
1069+ }
1070+
1071+ let query = city ;
1072+ if ( region ) {
1073+ if ( / u n i t e d s t a t e s | u s a | u s / i. test ( region ) ) {
1074+ query += ', USA' ;
1075+ } else {
1076+ query += `, ${ region } ` ;
1077+ }
1078+ }
1079+
1080+ const url = `https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&q=${ encodeURIComponent ( query ) } &limit=1` ;
1081+
1082+ try {
1083+ const response = await fetch ( url , { headers : { 'Accept-Language' : 'en' } } ) ;
1084+ if ( response . ok ) {
1085+ const results = await response . json ( ) ;
1086+ if ( results && results . length > 0 ) {
1087+ const r = results [ 0 ] ;
1088+ const address = r . address || { } ;
1089+ const result = {
1090+ country : address . country || 'Unknown' ,
1091+ city : address . city || address . town || address . village || city ,
1092+ latitude : parseFloat ( r . lat ) ,
1093+ longitude : parseFloat ( r . lon ) ,
1094+ flag : getCountryFlag ( ( address . country_code || '' ) . toUpperCase ( ) ) ,
1095+ countryCode : ( address . country_code || '' ) . toUpperCase ( )
1096+ } ;
1097+
1098+ saveGeoToCache ( key , result ) ;
1099+ return result ;
1100+ }
1101+ }
1102+ } catch ( error ) {
1103+ console . log ( 'Error geocoding city:' , city , error ) ;
1104+ }
1105+
1106+ return {
1107+ country : 'Unknown' ,
1108+ city : 'Unknown' ,
1109+ latitude : null ,
1110+ longitude : null ,
1111+ flag : '🏳️'
1112+ } ;
1113+ }
1114+
10501115 // Function to get country flag emoji from country code
10511116 function getCountryFlag ( countryCode ) {
10521117 if ( ! countryCode || countryCode . length !== 2 ) return '🏳️' ;
@@ -1332,28 +1397,39 @@ <h1>Galaxy Instance Map</h1>
13321397
13331398 const promises = currentData . map ( async ( row , index ) => {
13341399 const url = row [ 'URL' ] || row [ 'url' ] || '' ;
1335-
1336- if ( url && url . trim ( ) ) {
1337- try {
1338- const geoData = await getServerGeolocation ( url . trim ( ) , forceRefresh ) ;
1339- row [ 'GeoLocation' ] = geoData ;
1340- } catch ( error ) {
1341- console . error ( `Error geolocating ${ url } :` , error ) ;
1342- row [ 'GeoLocation' ] = {
1343- country : 'Unknown' ,
1344- city : 'Unknown' ,
1345- latitude : null ,
1346- longitude : null ,
1347- flag : '🏳️'
1348- } ;
1400+ const city = row [ 'city' ] || row [ 'City' ] || '' ;
1401+ const region = row [ 'Region' ] || row [ 'region' ] || '' ;
1402+
1403+ try {
1404+ let geoData = null ;
1405+
1406+ if ( city && city . trim ( ) ) {
1407+ geoData = await geocodeCityName ( city . trim ( ) , region , forceRefresh ) ;
13491408 }
1350- } else {
1351- row [ 'GeoLocation' ] = {
1352- country : 'Unknown' ,
1353- city : 'Unknown' ,
1354- latitude : null ,
1355- longitude : null ,
1356- flag : '🏳️'
1409+
1410+ if ( ! geoData || geoData . latitude === null || geoData . longitude === null ) {
1411+ if ( url && url . trim ( ) ) {
1412+ geoData = await getServerGeolocation ( url . trim ( ) , forceRefresh ) ;
1413+ } else {
1414+ geoData = {
1415+ country : 'Unknown' ,
1416+ city : 'Unknown' ,
1417+ latitude : null ,
1418+ longitude : null ,
1419+ flag : '🏳️'
1420+ } ;
1421+ }
1422+ }
1423+
1424+ row [ 'GeoLocation' ] = geoData ;
1425+ } catch ( error ) {
1426+ console . error ( `Error geolocating ${ url || city } :` , error ) ;
1427+ row [ 'GeoLocation' ] = {
1428+ country : 'Unknown' ,
1429+ city : 'Unknown' ,
1430+ latitude : null ,
1431+ longitude : null ,
1432+ flag : '🏳️'
13571433 } ;
13581434 }
13591435
0 commit comments