diff --git a/admin.php b/admin.php index f22a7b2..a6bc9df 100644 --- a/admin.php +++ b/admin.php @@ -373,12 +373,93 @@ function read_data($dir){ } return $data; } +function location_language_for_country($countryCode){ + $map = ['dk'=>'da','de'=>'de','at'=>'de','ch'=>'de','hr'=>'hr','se'=>'sv','no'=>'no','fi'=>'fi','pl'=>'pl','cz'=>'cs','sk'=>'sk','fr'=>'fr','it'=>'it','es'=>'es','pt'=>'pt','nl'=>'nl','be'=>'nl','ba'=>'bs','rs'=>'sr','si'=>'sl','hu'=>'hu','gb'=>'en','uk'=>'en','ie'=>'en']; + $countryCode = strtolower(trim((string)$countryCode)); + return $map[$countryCode] ?? 'en'; +} +function nominatim_reverse_json($lat, $lon, $language){ + $url = 'https://nominatim.openstreetmap.org/reverse?' . http_build_query(['format'=>'jsonv2','lat'=>sprintf('%.8F', $lat),'lon'=>sprintf('%.8F', $lon),'addressdetails'=>'1','accept-language'=>$language]); + $context = stream_context_create(['http'=>['method'=>'GET','header'=>'User-Agent: mvlog-admin/1.0 (reverse geocoding media metadata)\r\n','timeout'=>12]]); + $json = @file_get_contents($url, false, $context); + $data = $json !== false ? json_decode((string)$json, true) : null; + return is_array($data) ? $data : []; +} +function reverse_geocode_place($lat, $lon){ + $cacheFile = __DIR__ . '/cache/reverse-geocode.json'; + $cache = is_file($cacheFile) ? json_decode((string)file_get_contents($cacheFile), true) : []; + if (!is_array($cache)) $cache = []; + $key = sprintf('%.5F,%.5F', $lat, $lon); + if (isset($cache[$key]) && is_string($cache[$key])) return $cache[$key]; + $first = nominatim_reverse_json($lat, $lon, 'en'); + $countryCode = (string)($first['address']['country_code'] ?? ''); + $language = location_language_for_country($countryCode); + $data = ($language === 'en') ? $first : nominatim_reverse_json($lat, $lon, $language); + $address = is_array($data['address'] ?? null) ? $data['address'] : []; + $city = (string)($address['city'] ?? $address['town'] ?? $address['village'] ?? $address['island'] ?? $address['suburb'] ?? $address['hamlet'] ?? $address['municipality'] ?? ''); + $country = (string)($address['country'] ?? ''); + $place = trim(implode(', ', array_filter([$city, $country], fn($v)=>trim((string)$v) !== ''))); + if ($place === '') $place = trim($country); + if ($place !== '') { + $cache[$key] = $place; + @file_put_contents($cacheFile, json_encode($cache, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n", LOCK_EX); + @chmod($cacheFile, 0664); + } + return $place; +} +function media_gps_coordinates($path){ + $exiftool = trim((string)shell_exec('command -v exiftool 2>/dev/null')); + if ($exiftool === '' || !is_file($path)) return null; + $cmd = escapeshellarg($exiftool) . ' -json -n -GPSLatitude -GPSLongitude -GPSCoordinates ' . escapeshellarg($path) . ' 2>/dev/null'; + $rows = json_decode((string)shell_exec($cmd), true); + $row = is_array($rows) && isset($rows[0]) && is_array($rows[0]) ? $rows[0] : []; + $lat = $row['GPSLatitude'] ?? null; + $lon = $row['GPSLongitude'] ?? null; + if ((!is_numeric($lat) || !is_numeric($lon)) && !empty($row['GPSCoordinates']) && preg_match('/(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/', (string)$row['GPSCoordinates'], $m)) { + $lat = $m[1]; + $lon = $m[2]; + } + if (!is_numeric($lat) || !is_numeric($lon)) return null; + $lat = (float)$lat; + $lon = (float)$lon; + if (abs($lat) < 0.000001 && abs($lon) < 0.000001) return null; + return [$lat, $lon]; +} +function infer_location_from_first_media($dir){ + foreach (visual_order_files($dir) as $name) { + $gps = media_gps_coordinates($dir . '/' . $name); + if (!$gps) continue; + $place = reverse_geocode_place($gps[0], $gps[1]); + if ($place !== '') return $place; + } + return ''; +} +function display_month_year_from_media_datetime($value){ + $value = preg_replace('/[^0-9]/', '', (string)$value); + if (strlen($value) < 8) return ''; + $year = (int)substr($value, 0, 4); + $month = (int)substr($value, 4, 2); + $day = (int)substr($value, 6, 2); + if (!checkdate($month, $day, $year)) return ''; + return date('F Y', mktime(0, 0, 0, $month, $day, $year)); +} +function infer_date_from_first_media($dir){ + foreach (visual_order_files($dir) as $name) { + $date = media_file_date($dir . '/' . $name); + if ($date === null) continue; + $display = display_month_year_from_media_datetime($date); + if ($display !== '') return $display; + } + return ''; +} function write_data($dir, $post){ $title = trim($post['title'] ?? ''); $teaser = trim($post['teaser'] ?? ''); $quote_da = trim($post['quote_da'] ?? ''); $place = trim($post['place'] ?? ''); + if ($place === '') $place = infer_location_from_first_media($dir); $date = trim($post['date'] ?? ''); + if ($date === '') $date = infer_date_from_first_media($dir); $description = trim($post['description'] ?? ''); if (function_exists('mb_substr')) $description = mb_substr($description, 0, 5000, 'UTF-8'); else $description = substr($description, 0, 5000); $lines = [];