Skip to content

Instantly share code, notes, and snippets.

@Dan-Q
Created August 23, 2023 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Dan-Q/04dba4476a8157143694c7bc8d75d4d2 to your computer and use it in GitHub Desktop.
Save Dan-Q/04dba4476a8157143694c7bc8d75d4d2 to your computer and use it in GitHub Desktop.
Userscript to download all of the logs on a Geocaching.com cache page as JSON
// ==UserScript==
// @name Download JSON cachelogs
// @namespace dllogs.geocaching.danq.me
// @match https://www.geocaching.com/geocache/*
// @grant GM_registerMenuCommand
// @version 1.0
// @author Dan Q
// @description Download all logs against a particular Geocaching.com geocache as a JSON file
// ==/UserScript==
function downloadLogsWrapper(){
let logScroller;
let cycleDuration = 100;
let cyclesWaitedForLogsToLoad = 0;
let maxCyclesWaitedForLogsToLoad = 30;
let logScrollerDialog = document.createElement('dialog');
logScrollerDialog.style.position = 'fixed';
logScrollerDialog.style.left = 'calc(50% - 14vw)';
logScrollerDialog.style.top = 'calc(50% - 5vh)';
logScrollerDialog.style.height = '10vh';
logScrollerDialog.style.width = '28vw';
logScrollerDialog.style.display = 'grid';
logScrollerDialog.style.placeContent = 'center';
logScrollerDialog.style.textAlign = 'center';
document.body.appendChild(logScrollerDialog);
logScrollerDialog.innerHTML = 'Starting up...';
logScrollerDialog.showModal();
let footerRoot = document.getElementById('gc-footer-root');
function scrollToGetMoreLogs(){
logScrollerDialog.innerHTML = 'Scrolling to get more logs<br>';
footerRoot.scrollIntoView();
cyclesWaitedForLogsToLoad = 0;
clearInterval(logScroller);
logScroller = setInterval(maybeScrollToGetMoreLogs, cycleDuration);
}
function maybeScrollToGetMoreLogs(){
cyclesWaitedForLogsToLoad++;
logScrollerDialog.innerHTML += '.';
let needToScroll = footerRoot.getBoundingClientRect().top > window.innerHeight;
if(!needToScroll) {
if(cyclesWaitedForLogsToLoad >= maxCyclesWaitedForLogsToLoad) {
clearInterval(logScroller);
downloadLogs();
}
return;
}
scrollToGetMoreLogs();
}
// kickstart process:
setTimeout(scrollToGetMoreLogs, 100);
function downloadLogs(){
logScrollerDialog.innerHTML = 'Downloading logs as JSON';
let gcCode = document.getElementById('ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode').innerText.trim();
let logData = Array.from(document.querySelectorAll('#cache_logs_table tbody tr')).map(tr=>{
const author = tr.querySelector('.h5');
return {
cache: {
name: document.getElementById('ctl00_ContentBody_CacheName').innerText.trim(),
code: gcCode,
type: document.querySelector('.cacheImage').attributes.title.value.trim(),
},
author: {
name: author.innerText.trim(),
guid: author.href.replace(/^.*\/profile\/\?guid=/, ''),
premium: !!author.nextElementSibling.innerText.match(/Premium/),
},
log: {
type: tr.querySelector('.h4').innerText.trim(),
text: tr.querySelector('.LogText').innerText.trim(),
date: tr.querySelector('.LogDate').innerText.trim(),
luid: tr.querySelector('a[title="View Log"]').href.replace(/^.*\/seek\/log\.aspx\?LUID=/, ''),
},
};
});
let logDataEncoded = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(logData))}`;
let logDataLink = document.createElement('a');
logDataLink.setAttribute("href", logDataEncoded);
logDataLink.setAttribute("download", `${gcCode}.logs.json`);
logDataLink.click();
setTimeout(()=>logScrollerDialog.remove(), 1000);
}
}
GM_registerMenuCommand('Download logs', downloadLogsWrapper);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment