import axios from 'axios'; import * as cheerio from 'cheerio'; import https from 'https'; import fs from 'fs'; import path from 'path'; import { lakesConfig } from './lakesConfig'; async function fixLevels() { const agent = new https.Agent({ rejectUnauthorized: false }); const updatedConfig = [...lakesConfig]; for (let i = 0; i < updatedConfig.length; i++) { const lake = updatedConfig[i]; // id is like SPKA|1 -> internalId is SPKA, oid is 1 const parts = lake.id.split('|'); if (parts.length !== 2) continue; const internalId = parts[0]; const oid = parts[1]; const url = `https://www.pvl.cz/portal/nadrze/cz/pc/Mereni.aspx?id=${internalId}&oid=${oid}`; try { const response = await axios.get(url, { httpsAgent: agent, headers: { 'User-Agent': 'Mozilla/5.0' } }); const $ = cheerio.load(response.data); let maxRet: number | null = null; let minStale: number | null = null; let maxVol: number | null = null; $('table').each((_, tbl) => { const text = $(tbl).text(); // Parse levels if (text.includes('Maximální retenční hladina:')) { $(tbl).find('tr').each((_, row) => { const rowText = $(row).text().replace(/\\s+/g, ' '); if (rowText.includes('Maximální retenční hladina:')) { const val = parseFloat(rowText.replace('Maximální retenční hladina:', '').replace('[m n.m.]', '').replace(',', '.').trim()); if (!isNaN(val)) maxRet = val; } if (rowText.includes('Hladina stálého nadržení:')) { const val = parseFloat(rowText.replace('Hladina stálého nadržení:', '').replace('[m n.m.]', '').replace(',', '.').trim()); if (!isNaN(val)) minStale = val; } }); } // Parse volume (this is current volume, wait, does PVL show max volume? Usually no, but current volume might be bigger than our guessed maxVolume) if (text.includes('Aktuální hodnoty') && text.includes('Objem')) { $(tbl).find('tr').each((_, row) => { const rowText = $(row).text().replace(/\\s+/g, ' '); if (rowText.includes('Objem [mil. m3]')) { const valStr = $(row).find('td').eq(1).text().trim().replace(',', '.'); const val = parseFloat(valStr); if (!isNaN(val)) maxVol = val; // We will just use the current volume as a baseline if it's bigger than our maxVolume } }); } }); if (maxRet) updatedConfig[i].maxLevel = maxRet; if (minStale) updatedConfig[i].minLevel = minStale; // For volume, if the current volume is larger than the configured maxVolume, increase maxVolume if (maxVol && updatedConfig[i].maxVolume && maxVol > updatedConfig[i].maxVolume!) { updatedConfig[i].maxVolume = Math.ceil(maxVol * 1.2 * 10) / 10; // add 20% buffer } else if (maxVol && !updatedConfig[i].maxVolume) { updatedConfig[i].maxVolume = Math.ceil(maxVol * 1.5 * 10) / 10; } console.log(`Updated ${lake.text}: min=${minStale}, max=${maxRet}, vol=${maxVol} -> newMaxVol=${updatedConfig[i].maxVolume}`); } catch (err: any) { console.error(`Failed for ${lake.text}: ${err.message}`); } } // Generate new file content let newContent = `export interface LakeConfig { id: string; text: string; priority?: boolean; coords: [number, number]; maxVolume?: number; minLevel?: number; maxLevel?: number; storageLevel?: number; } export const lakesConfig: LakeConfig[] = [ `; updatedConfig.forEach((l, idx) => { newContent += ` { id: "${l.id}", text: "${l.text}", ${l.priority ? 'priority: true, ' : ''}coords: [${l.coords[0].toFixed(4)}, ${l.coords[1].toFixed(4)}], maxVolume: ${l.maxVolume}, minLevel: ${l.minLevel}, maxLevel: ${l.maxLevel}, storageLevel: ${l.storageLevel} }${idx === updatedConfig.length - 1 ? '' : ','}\\n`; }); newContent += `];\\n`; fs.writeFileSync(path.resolve('./scripts/lakesConfig.ts'), newContent); console.log("lakesConfig.ts updated!"); } fixLevels();