// API communication functions async function scrapeNextListing() { if (!AppState.currentSessionId || !AppState.isScrapingActive) { console.log('Scraping stopped: session or active flag cleared'); return false; } try { const response = await fetch(`${API_BASE_URL}/api/scrape/${AppState.currentSessionId}`); const data = await response.json(); if (data.cancelled) { console.log('Scraping cancelled by backend'); return false; } if (data.listing) { AppState.allListings.push(data.listing); addMarker(data.listing); // Update display const sortBy = document.getElementById('sortSelect').value; const sortedListings = sortListings(AppState.allListings, sortBy); renderResults(sortedListings); // Fit map to markers if (AppState.markers.length > 0) { const group = L.featureGroup(AppState.markers); AppState.map.fitBounds(group.getBounds().pad(0.1)); } } updateProgress(data.progress.current, data.progress.total); if (data.complete) { console.log('Scraping complete, finalizing...'); AppState.isScrapingActive = false; document.getElementById('searchBtn').disabled = false; document.getElementById('cancelBtn').style.display = 'none'; updateProgress(0, 0); showStatus(`Fertig! ${AppState.allListings.length} Inserate geladen`, 'success'); console.log('Final listings count:', AppState.allListings.length); return false; } return true; } catch (error) { console.error('Scrape error:', error); AppState.isScrapingActive = false; document.getElementById('searchBtn').disabled = false; document.getElementById('cancelBtn').style.display = 'none'; showStatus('Fehler beim Laden der Inserate', 'error'); return false; } } async function startScrapingLoop() { while (AppState.isScrapingActive && AppState.currentSessionId) { const shouldContinue = await scrapeNextListing(); if (!shouldContinue) { break; } await new Promise(resolve => setTimeout(resolve, 100)); } } async function searchListings() { const searchTerm = document.getElementById('searchTerm').value.trim(); const minPrice = parseInt(document.getElementById('minPrice').value) || 0; const maxPriceInput = document.getElementById('maxPrice').value; const maxPrice = maxPriceInput ? parseInt(maxPriceInput) : 1000000000; const numListings = parseInt(document.getElementById('numListings').value) || 25; const powerSearchDescriptionTerm = document.getElementById('powerSearchDescTerm').value.trim(); if (!searchTerm) { showStatus('Bitte Suchbegriff eingeben', 'error'); return; } document.getElementById('searchBtn').disabled = true; clearMarkers(); AppState.allListings = []; AppState.selectedListingId = null; document.getElementById('resultsList').innerHTML = ''; showStatus('Suche nach Inseraten...', 'loading'); try { const response = await fetch(`${API_BASE_URL}/api/search`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ search_term: searchTerm, min_price: minPrice, max_price: maxPrice, num_listings: numListings, search_term_desc: powerSearchDescriptionTerm }) }); if (!response.ok) { throw new Error('API request failed'); } const data = await response.json(); AppState.currentSessionId = data.session_id; if (data.total === 0) { showStatus('Keine Inserate gefunden', 'error'); document.getElementById('searchBtn').disabled = false; return; } showStatus(`${data.total} Inserate gefunden. Lade Details...`, 'success'); // Show cancel button document.getElementById('cancelBtn').style.display = 'inline-block'; // Start scraping AppState.isScrapingActive = true; AppState.scrapeStartTime = Date.now(); updateProgress(0, data.total); startScrapingLoop(); } catch (error) { console.error('Search error:', error); showStatus('Fehler: Verbindung zum Server fehlgeschlagen', 'error'); document.getElementById('searchBtn').disabled = false; } } async function cancelScraping() { if (!AppState.currentSessionId) return; try { await fetch(`${API_BASE_URL}/api/scrape/${AppState.currentSessionId}/cancel`, { method: 'POST' }); AppState.isScrapingActive = false; document.getElementById('searchBtn').disabled = false; document.getElementById('cancelBtn').style.display = 'none'; updateProgress(0, 0); showStatus(`Abgebrochen. ${AppState.allListings.length} Inserate geladen`, 'error'); } catch (error) { console.error('Cancel error:', error); } }