Instantly share code, notes, and snippets.
Last active
May 30, 2022 02:22
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save d3m3vilurr/2729f57c59d70b657d3448f03f2248bf to your computer and use it in GitHub Desktop.
Inject GPX link to Naver bike route map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Inject GPX link to Naver MAP | |
// @namespace https://map.naver.com | |
// @updateURL https://gist.github.com/d3m3vilurr/2729f57c59d70b657d3448f03f2248bf/raw/inject_gpx_link_to_naver_map.user.js | |
// @downloadURL https://gist.github.com/d3m3vilurr/2729f57c59d70b657d3448f03f2248bf/raw/inject_gpx_link_to_naver_map.user.js | |
// @version 0.4 | |
// @description Add GPX route link for bike | |
// @author Sunguk Lee <[email protected]> | |
// @match https://map.naver.com/* | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// hack restore console log | |
// var i = document.createElement('iframe'); | |
// i.style.display = 'none'; | |
// document.body.appendChild(i); | |
// window.console = i.contentWindow.console; | |
const XHR = XMLHttpRequest; | |
function makeGPXXML(summary, routes, guides) { | |
const lines = [ | |
'<?xml version="1.0" encoding="UTF-8"?>', | |
'<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxdata="http://www.cluetrust.com/XML/GPXDATA/1/0" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.cluetrust.com/XML/GPXDATA/1/0 http://www.cluetrust.com/Schemas/gpxdata10.xsd" version="1.1" creator="http://ridewithgps.com/">', | |
' <metadata>', | |
` <name>${summary.name}</name>`, | |
` <time>${new Date().toISOString()}</time>`, | |
' </metadata>', | |
' <trk>', | |
` <name>${summary.name}</name>`, | |
' <trkseg>', | |
]; | |
for (const route of routes) { | |
lines.push(` <trkpt lat="${route.lat}" lon="${route.lon}"></trkpt>`); | |
} | |
lines.push(' </trkseg>'); | |
lines.push(' </trk>'); | |
lines.push(' <rte>'); | |
for (const wpt of guides) { | |
lines.push(` <rtept lat="${wpt.lat}" lon="${wpt.lon}">`); | |
lines.push(` <name>${wpt.name}</name>`); | |
lines.push(` <desc>${wpt.desc}</desc>`); | |
lines.push(' </rtept>'); | |
} | |
lines.push(' </rte>'); | |
//for (const wpt of guides) { | |
// lines.push(` <wpt lat="${wpt.lat}" lon="${wpt.lon}">`); | |
// lines.push(` <name>${wpt.name}</name>`); | |
// lines.push(` <desc>${wpt.desc}</desc>`); | |
// lines.push(' </wpt>'); | |
//} | |
lines.push('</gpx>'); | |
return lines.join('\n'); | |
} | |
const sleep = (ms) => { | |
return new Promise((res, rej) => { | |
setTimeout(() => { res(); }, ms); | |
}); | |
}; | |
const parseGuide = (guide) => { | |
const [lon, lat] = guide.turn_point.split(',').map((v) => parseFloat(v)); | |
const desc = guide.instructions.replace(/(<([^>]+)>)/gi, ""); | |
return { | |
name: guide.point || desc, | |
desc: desc, | |
lat, lon, | |
}; | |
}; | |
async function handleToMakeGPXLink(e) { | |
const xhr = e.target; | |
if (xhr.status != 200) { | |
return; | |
} | |
if (!xhr.responseURL.includes('findbicycle')) { | |
return; | |
} | |
let json; | |
try { | |
json = JSON.parse(xhr.responseText); | |
// console.log(json); | |
} catch (e) { | |
return; | |
} | |
let docItems = document.getElementsByTagName('directions-summary-item-bike'); | |
console.log(docItems); | |
if (!docItems.length) { | |
return; | |
} | |
await sleep(1000); | |
for (const idx in json.routes) { | |
const route = json.routes[idx]; | |
const docItem = docItems[idx].getElementsByClassName('summary_box')[0]; | |
console.log(docItem); | |
// console.log('from:', route.summary.start.address); | |
// console.log('to:', route.summary.end.address); | |
// console.log('distance:', route.summary.distance); | |
//const waypoints = []; | |
const routes = []; | |
const guides = []; | |
//for (const waypoint of route.waypoints) { | |
// const [lon, lat] = waypoint.location.split(',').map((v) => parseFloat(v)); | |
// waypoints.append({ | |
// name: waypoint.address, | |
// lat, | |
// lon, | |
// }); | |
//} | |
for (const leg of route.legs) { | |
for (const step of leg.steps) { | |
// if (step.guide.turn_point) { | |
// const [lon,lat] = step.guide.turn_point.split(',').map((v) => parseFloat(v)); | |
// routes.push({lat, lon}); | |
// } | |
const paths = step.path.split(' '); | |
for (const path of paths) { | |
if (!path) { | |
continue; | |
} | |
const [lon,lat] = path.split(',').map((v) => parseFloat(v)); | |
routes.push({lat, lon}); | |
} | |
guides.push(parseGuide(step.guide)); | |
} | |
} | |
// console.log('routes:', routes); | |
// console.log('guides:', guides); | |
route.summary.name = `${route.summary.start.address}_${route.summary.end.address}`; | |
const xml = makeGPXXML(route.summary, routes, guides); | |
const elem = document.createElement('a'); | |
elem.setAttribute('href', 'data:text/plain;charset=utf-8,'+encodeURIComponent(xml)); | |
elem.setAttribute('download', `${route.summary.name}.gpx`); | |
elem.innerHTML = '<img src="https://upload.wikimedia.org/wikipedia/commons/e/e3/Gpx_icon.png" width="18" height="18" />' | |
// console.log(elem); | |
const span = document.createElement('span'); | |
span.classList.add('summary_subtitle'); | |
span.style.margin = "0 0 0 6px"; | |
span.appendChild(elem); | |
docItem.appendChild(span); | |
} | |
} | |
class NaverMap2GPXXMLHttpRequest extends XHR { | |
send(body) { | |
// inject listener to hooking the loaded data | |
this.addEventListener('loadend', handleToMakeGPXLink); | |
return super.send(body); | |
} | |
} | |
window.XMLHttpRequest = NaverMap2GPXXMLHttpRequest; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment