Geocaching Puzzle Helper

Show hidden user-added elements on Geocaching Mystery Cache Page

目前為 2024-12-26 提交的版本,檢視 最新版本

// ==UserScript==
// @name Geocaching Puzzle Helper
// @description Show hidden user-added elements on Geocaching Mystery Cache Page
// @match http://www.geocaching.com/geocache/*
// @match https://www.geocaching.com/geocache/*
// @match http://geocaching.com/geocache/*
// @match https://geocaching.com/geocache/*
// @version 1.21
// @namespace https://gf.qytechs.cn/en/scripts/464566-geocaching-puzzle-helper
// @homepage https://gf.qytechs.cn/en/scripts/464566-geocaching-puzzle-helper
// @license MIT
// ==/UserScript==
/* Features
-- Add several links to the map links
-- Checks if cache is at posted coordinates and adds a function to the top to quick replace
-- Show coordinate in decimal format
-- Present button to highlight comments, white text, link and hidden link information
*/

(function () {
    'use strict';

    // Entry point
    const descriptions = [
        "ctl00_ContentBody_ShortDescription",
        "ctl00_ContentBody_LongDescription",
    ];
    descriptions.forEach(id => scanElemForStuff(document.getElementById(id)));

    showFinalLocation();
    addCustomLink("Ingress", buildIngressURL());
    addCustomLink("HMDB", buildHMDBURL());
    addCustomLink("NowListenToMe", buildNowListenToMeURL());
    appendDecimalMinutes();

    /**
     * Appends decimal minutes to the location panel.
     */
    function appendDecimalMinutes() {
        const elem = document.getElementById("ctl00_ContentBody_LocationSubPanel");
        if (elem) {
            elem.innerText += `DEC: ${mapLatLng.lat}, ${mapLatLng.lng}\n`;
        }
    }

    /**
     * Adds a custom link to the map links section.
     * @param {string} name - The name of the link.
     * @param {string} url - The URL for the link.
     */
    function addCustomLink(name, url) {
        const mapLinks = document.getElementById("ctl00_ContentBody_MapLinks_MapLinks");
        if (mapLinks) {
            const list = mapLinks.querySelector('ul');
            const listItem = document.createElement('li');
            const link = document.createElement('a');
            link.setAttribute("target", "_blank");
            link.href = url;
            link.innerText = name;
            listItem.appendChild(link);
            list.appendChild(listItem);
        }
    }

    /**
     * Builds the Ingress link URL.
     */
    function buildIngressURL() {
        return `https://intel.ingress.com/intel?ll=${mapLatLng.lat},${mapLatLng.lng}&z=16`;
    }

    /**
     * Builds the HMDB link URL.
     */
    function buildHMDBURL() {
        return `https://www.hmdb.org/results.asp?Search=Proximity&SearchFor=${mapLatLng.lat},${mapLatLng.lng}&Miles=10&MilesType=1&HistMark=Y&WarMem=Y`;
    }

    /**
     * Builds the NowListenToMe link URL.
     */
    function buildNowListenToMeURL() {
        return `http://nowlistento.me/geocalc?StartCoord=${mapLatLng.lat},${mapLatLng.lng}&z=16`;
    }

    /**
     * Scans an element for hosted links, extra text, links, white text, and comments.
     * @param {HTMLElement} elem - The element to scan.
     */
    function scanElemForStuff(elem) {
        if (!elem) return;

        [
            { label: "Hosted", getData: getHostedLinks },
            { label: "Extra", getData: getExtraText },
            { label: "Links", getData: getAllLinks },
            { label: "White Text", getData: getWhiteText },
            { label: "Comments", getData: getAllComments },
        ].forEach(({ label, getData }) => {
            const data = getData(elem);
            if (data.length > 0) {
                addButton(elem, label, data.join('\r\n'), onClickHandler);
            }
        });
    }

    /**
     * Adds a button to a parent element.
     */
    function addButton(parent, text, title, onclick, append = false) {
        const button = document.createElement('button');
        button.innerHTML = text;
        button.title = title;
        button.onclick = onclick;
        button.addEventListener('contextmenu', e => e.preventDefault());
        append ? parent.appendChild(button) : parent.insertBefore(button, parent.firstChild);
    }

    // Utility functions for data extraction
    function getAllComments(rootElem) {
        const iterator = document.createNodeIterator(rootElem, NodeFilter.SHOW_COMMENT, null, false);
        const comments = [];
        let curNode;
        while ((curNode = iterator.nextNode())) {
            comments.push(curNode.nodeValue);
        }
        return comments;
    }

    function getAllLinks(rootElem) {
        return Array.from(rootElem.getElementsByTagName('a')).map(link => link.href);
    }

    function getHostedLinks(rootElem) {
        const imgs = Array.from(rootElem.getElementsByTagName('img'));
        return imgs
            .map(img => img.src.toLowerCase())
            .filter(src =>
                (!src.includes("s3.amazonaws.com/gs-geo-images") &&
                    !src.includes(".geocaching.com") &&
                    !src.includes(".groundspeak.com")) ||
                src.includes("?")
            );
    }

    function getWhiteText(rootElem) {
        const whiteColors = ["#ffffff", "white", "rgb(255, 255, 255)"];
        return Array.from(rootElem.getElementsByTagName("*"))
            .filter(el => whiteColors.includes(el.style.color) || whiteColors.includes(el.getAttribute("color")))
            .map(el => el.innerHTML);
    }

    function getExtraText(rootElem) {
        const attributes = ["alt", "name", "id", "title"];
        return Array.from(rootElem.getElementsByTagName("*"))
            .flatMap(el => attributes.map(attr => el.getAttribute(attr)).filter(Boolean));
    }

    /**
     * Handles click events for buttons.
     */
    function onClickHandler(e) {
        alert(this.title);
        return false;
    }

    /**
     * Displays the final location if available.
     */
    function showFinalLocation() {
        const elem = document.getElementById("awpt_FN");
        if (!elem) return;

        const coordElem = elem.parentNode?.nextElementSibling?.nextElementSibling?.nextElementSibling;
        if (coordElem && coordElem.innerText.length > 4) {
            const locElem = document.getElementById("uxLatLonLink");
            if (locElem) {
                addButton(locElem, "FN", coordElem.innerText, onClickHandler, true);
            }
        }
    }
})();

QingJ © 2025

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