const https = require('https'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const CACHE_DIR = path.join(__dirname, '..', 'cache'); // Ensure cache directory exists if (!fs.existsSync(CACHE_DIR)) { fs.mkdirSync(CACHE_DIR, { recursive: true }); } /** * Generate a safe filename from a city query * @param {string} cityQuery - City name * @returns {string} Safe filename */ function getCacheFileName(cityQuery) { const hash = crypto.createHash('md5').update(cityQuery.toLowerCase().trim()).digest('hex'); return `geocode_${hash}.json`; } /** * Get cached geocode data if available * @param {string} cityQuery - City name * @returns {Object|null} Cached data or null */ function getCachedGeocode(cityQuery) { try { const cacheFile = path.join(CACHE_DIR, getCacheFileName(cityQuery)); if (fs.existsSync(cacheFile)) { const data = fs.readFileSync(cacheFile, 'utf8'); const cached = JSON.parse(data); // Verify the query matches if (cached.query && cached.query.toLowerCase().trim() === cityQuery.toLowerCase().trim()) { console.log(`Geocode: ${cityQuery} (cached)`); return cached; } } } catch (error) { // Silent fail } return null; } /** * Save geocode data to cache * @param {string} cityQuery - City name * @param {Object} data - Geocode data to cache */ function saveCachedGeocode(cityQuery, data) { try { const cacheFile = path.join(CACHE_DIR, getCacheFileName(cityQuery)); fs.writeFileSync(cacheFile, JSON.stringify(data, null, 2), 'utf8'); } catch (error) { // Silent fail } } /** * Geocode city to lat/lon using Nominatim (OpenStreetMap) * @param {string} cityQuery - City name to geocode * @returns {Promise<{lat: number, lon: number, displayName: string}>} */ async function geocodeCity(cityQuery) { // Check cache first const cached = getCachedGeocode(cityQuery); if (cached) { return cached; } return new Promise((resolve, reject) => { const encodedQuery = encodeURIComponent(cityQuery); const url = `https://nominatim.openstreetmap.org/search?q=${encodedQuery}&format=json&limit=1`; const options = { headers: { 'User-Agent': 'webpage-to-hls-streaming-app/1.0' } }; https.get(url, options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const results = JSON.parse(data); if (results && results.length > 0) { const geocodeResult = { query: cityQuery, lat: parseFloat(results[0].lat), lon: parseFloat(results[0].lon), displayName: results[0].display_name }; console.log(`Geocode: ${cityQuery} -> ${geocodeResult.displayName} (API)`); // Save to cache saveCachedGeocode(cityQuery, geocodeResult); resolve(geocodeResult); } else { reject(new Error('No results found')); } } catch (error) { reject(error); } }); }).on('error', (error) => { reject(error); }); }); } module.exports = { geocodeCity };