WDFW Overabundant Lakes KML Exporter)

Export all WDFW Overabundant Lakes to KML (using AJAX)

// ==UserScript==
// @name         WDFW Overabundant Lakes KML Exporter)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Export all WDFW Overabundant Lakes to KML (using AJAX)
// @match        https://wdfw.wa.gov/fishing/locations/high-lakes/overabundant*
// @license      GNU GPLv3
// @connect      wdfw.wa.gov
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';

    let totalLakes = 0;
    let processedLakes = 0;

    function waitForTableAndCreateButton() {
        const table = document.querySelector('table tbody');
        if (!table) {
            setTimeout(waitForTableAndCreateButton, 500); // Retry in 0.5s
            return;
        }
        createButton();
    }

    function createButton() {
        const btn = document.createElement('button');
        btn.textContent = 'Download All Lakes as KML';
        btn.style.position = 'fixed';
        btn.style.top = '10px';
        btn.style.right = '10px';
        btn.style.zIndex = '9999';
        btn.style.padding = '10px 15px';
        btn.style.background = '#4CAF50';
        btn.style.color = 'white';
        btn.style.border = 'none';
        btn.style.borderRadius = '5px';
        btn.style.fontSize = '16px';
        btn.style.cursor = 'pointer';
        btn.onclick = exportAllLakesToKML;
        document.body.appendChild(btn);

        // Create status bar
        const statusDiv = document.createElement('div');
        statusDiv.id = 'status-bar';
        statusDiv.style.position = 'fixed';
        statusDiv.style.top = '60px';
        statusDiv.style.right = '10px';
        statusDiv.style.zIndex = '9999';
        statusDiv.style.background = '#fff';
        statusDiv.style.padding = '10px';
        statusDiv.style.borderRadius = '5px';
        statusDiv.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
        statusDiv.style.width = '250px';
        statusDiv.innerHTML = `Total Lakes: <span id="total-lakes">0</span><br>Processed: <span id="processed-lakes">0</span><br>Progress: <span id="progress">0%</span>`;
        document.body.appendChild(statusDiv);
    }

    function exportAllLakesToKML() {
        let kmlContent = `<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>\n`;

        let pagesProcessed = 0;
        let totalPages = 0;
        let allLinks = [];

        // Determine the total number of pages
        const lastPageLink = document.querySelector('.pager__item--last a');
        if (lastPageLink) {
            totalPages = parseInt(lastPageLink.href.match(/page=(\d+)/)[1]) + 1; // Total pages are 0-indexed
        }

        console.log(`Total pages: ${totalPages}`);

        // Loop through all pages
        for (let page = 0; page < totalPages; page++) {
            const pageUrl = `https://wdfw.wa.gov/fishing/locations/high-lakes/overabundant?name=&species=&page=${page}`;
            GM_xmlhttpRequest({
                method: 'GET',
                url: pageUrl,
                onload: function(response) {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(response.responseText, 'text/html');
                    const rows = doc.querySelectorAll('table tbody tr');
                    const lakeLinks = Array.from(rows).map(row => row.querySelector('td a').href);
                    allLinks.push(...lakeLinks);

                    console.log(`Page ${page + 1} processed. Lakes found: ${lakeLinks.length}`);

                    // Check if all pages have been processed
                    pagesProcessed++;
                    if (pagesProcessed === totalPages) {
                        console.log("All pages processed. Starting to fetch lake details...");
                        totalLakes = allLinks.length;
                        updateStatusBar();
                        fetchLakeDetails(allLinks, kmlContent);
                    }
                }
            });
        }


    }

    function fetchLakeDetails(lakeLinks, kmlContent) {
        let processed = 0;

        console.log("Fetching lake details...");

        lakeLinks.forEach(link => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: link,
                onload: function(response) {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(response.responseText, 'text/html');
                    processLakePage(doc, (lakeKML) => {
                        kmlContent += lakeKML;
                        processed++;
                        processedLakes++;
                        updateStatusBar();
                        if (processed === lakeLinks.length) {
                            kmlContent += `</Document>\n</kml>`;
                            downloadKML(kmlContent);
                        }
                    });
                }
            });
        });
    }

    function processLakePage(doc, callback) {
        const name = doc.querySelector('h1').innerText.trim();

        // Extract the County, Acreage, Elevation, and Location from the <p> tag.
        const infoText = doc.querySelector('p').innerText;
        const countyMatch = infoText.match(/County:\s*([\w\s]+)/);
        const acreageMatch = infoText.match(/Acreage:\s*([\d.]+ ac)/);
        const elevationMatch = infoText.match(/Elevation:\s*([\d]+ ft)/);
        const locationMatch = infoText.match(/Center:\s*([\d.-]+,\s*[\d.-]+)/);

        const county = countyMatch ? countyMatch[1].trim() : '';
        const acres = acreageMatch ? acreageMatch[1].trim() : '';
        const elevation = elevationMatch ? elevationMatch[1].trim() : '';
        const location = locationMatch ? locationMatch[1].trim().split(',') : [];

        const lat = location[0] ? location[0].trim() : '';
        const lon = location[1] ? location[1].trim() : '';

        // Extract Species from the Species list
        const speciesList = [];
        const speciesItems = doc.querySelectorAll('li.field-item');
        speciesItems.forEach(item => {
            speciesList.push(item.innerText.trim());
        });
        const species = speciesList.join(', ');

        // Format the KML Placemark for this lake
        const lakeKML = `
            <Placemark>
                <name>${name}</name>
                <description><![CDATA[County: ${county}<br/>Acreage: ${acres}<br/>Elevation: ${elevation}<br/>Species: ${species}]]></description>
                <Point><coordinates>${lon},${lat},0</coordinates></Point>
            </Placemark>
        `;

        callback(lakeKML);
    }

    function updateStatusBar() {
        const totalLakesSpan = document.getElementById('total-lakes');
        const processedLakesSpan = document.getElementById('processed-lakes');
        const progressSpan = document.getElementById('progress');
        const progress = totalLakes > 0 ? Math.round((processedLakes / totalLakes) * 100) : 0;

        totalLakesSpan.textContent = totalLakes;
        processedLakesSpan.textContent = processedLakes;
        progressSpan.textContent = `${progress}%`;
    }

    function downloadKML(kmlContent) {
        const blob = new Blob([kmlContent], {type: 'application/vnd.google-earth.kml+xml'});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'wdfw_overabundant_lakes.kml';
        a.click();
        URL.revokeObjectURL(url);
    }

    waitForTableAndCreateButton();
})();