AllTrails KML Downloader

This script adds a "Download KML" button to any trail on AllTrails.com

目前为 2025-04-29 提交的版本,查看 最新版本

// ==UserScript==
// @name         AllTrails KML Downloader
// @namespace    http://tampermonkey.net/
// @version      2025-04-29
// @description  This script adds a "Download KML" button to any trail on AllTrails.com
// @match        https://www.alltrails.com/trail/*
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @require      https://cdnjs.cloudflare.com/ajax/libs/mapbox-polyline/1.1.1/polyline.min.js
// @license      GNU GPLv3
// ==/UserScript==

(function() {
    'use strict';

    // Add the "Download KML" button to the page
    function createDownloadButton() {
        const button = document.createElement('button');
        button.textContent = 'Download KML';
        button.style.position = 'fixed';
        button.style.top = '10px';
        button.style.right = '10px';
        button.style.zIndex = '9999';
        button.style.padding = '10px 15px';
        button.style.background = '#4CAF50';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.fontSize = '16px';
        button.style.cursor = 'pointer';

        button.onclick = function() {
            fetchMapPageAndGenerateKML();
        };

        document.body.appendChild(button);
    }

    // Function to fetch map data via AJAX from the map page URL
    function fetchMapPageAndGenerateKML() {
        const trailUrl = window.location.href;  // e.g., "https://www.alltrails.com/trail/us/florida/lake-myakka-trail"
        const mapUrl = trailUrl.replace('/trail/', '/explore/trail/') + '?mobileMap=false&initFlyover=true&flyoverReturnToTrail';

        console.log(`Fetching map data from: ${mapUrl}`);

        GM_xmlhttpRequest({
            method: 'GET',
            url: mapUrl,
            onload: function(response) {
                const mapPageHtml = response.responseText;
                const mapDataMatch = mapPageHtml.match(/<div data-react-class="SearchApp" data-react-props="({.+?})"/);

                if (mapDataMatch && mapDataMatch[1]) {
                    const mapDataJson = JSON.parse(mapDataMatch[1].replace(/&quot;/g, '"'));
                    generateKML(mapDataJson);
                } else {
                    console.error('Failed to extract map data');
                }
            },
            onerror: function() {
                console.error('Error fetching map page.');
            }
        });
    }

    // Convert the map data to KML format
    function generateKML(mapData) {
        const trailName = mapData.initialExploreMap.name;
        const waypoints = mapData.initialExploreMap.waypoints;
        const routes = mapData.initialExploreMap.routes;

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

        // Add routes (trails)
        routes.forEach(route => {
            route.lineSegments.forEach(segment => {
                const pointsData = segment.polyline.pointsData;

                // Decode the polyline (if pointsData is not already decoded)
                if (typeof pointsData === 'string') {
                    const decodedPoints = polyline.decode(pointsData);
                    let coordinates = decodedPoints.map(point => `${point[1]},${point[0]},0`).join(' ');
                    kmlContent += `
                    <Placemark>
                        <name>${trailName}</name>
                        <description><![CDATA[${window.location.href}]]></description>
                        <LineString>
                            <coordinates>${coordinates}</coordinates>
                        </LineString>
                    </Placemark>
                    `;
                } else {
                    console.error('pointsData is not a polyline string:', pointsData);
                }
            });
        });

        // Add waypoints (trail markers)
        waypoints.forEach(waypoint => {
            kmlContent += `
            <Placemark>
                <name>${waypoint.name}</name>
                <Point>
                    <coordinates>${waypoint.location.longitude},${waypoint.location.latitude},0</coordinates>
                </Point>
                <description><![CDATA[${waypoint.description || ''}]]></description>
            </Placemark>
            `;
        });

        kmlContent += `</Document>\n</kml>`;

        // Trigger KML download
        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 = `${trailName}.kml`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    // Initialize the script
    createDownloadButton();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址