diff --git a/.gitignore b/.gitignore index 208f440..af0faab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *~ .DS_Store *.swp -web-ext-artifacts diff --git a/README.md b/README.md index 5e58206..8659703 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # SAC Route Portal GPX Downloader + The [Swiss Alpine Club](https://www.sac-cas.ch/en/) has a great [route portal](https://www.sac-cas.ch/en/huts-and-tours/sac-route-portal/) for finding interesting hiking routes. @@ -18,6 +19,3 @@ Heed their warning and do not blindly follow the gps track! Use your brain and plan your route beforehand to be aware of dangerous parts and alternatives. Take a look at their [safety instructions](https://www.sac-cas.ch/en/training-and-safety/safety/). - -## Contributors -- wizche diff --git a/background.js b/background.js index e03772c..75da0bd 100644 --- a/background.js +++ b/background.js @@ -1,255 +1,196 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - + let gpxTrack = null; /** * Convert the Swiss projection coordinates to WGS84 (lat/lon). - * - * Calculations from "Approximate formulas for the transformation between Swiss - * projection coordinates and WGS84" by the Swiss Federal Office of Topography, - * swisstopo + * + * Calculations from "Approximate formulas for the transformation between Swiss + * projection coordinates and WGS84" by the Swiss Federal Office of Topography, + * swisstopo * (https://www.swisstopo.admin.ch/en/knowledge-facts/surveying-geodesy/reference-systems/map-projections.html). - * - * @param {*} point Array of Swiss projection coordinates, position 0 is E and 1 is N. - * @returns Calculated lat and lon. - */ -function toWGS84(point) { - // convert LV95 into the civilian system - const y_aux = (point[0] - 2600000) / 1000000; - const x_aux = (point[1] - 1200000) / 1000000; - - // calculate longitude and latitude in the unit 10000" - let lat = 16.9023892 + - 3.238272 * x_aux - - 0.270978 * Math.pow(y_aux, 2) - - 0.002528 * Math.pow(x_aux, 2) - - 0.0447 * Math.pow(y_aux, 2) * x_aux - - 0.014 * Math.pow(x_aux, 3); - - let lon = 2.6779094 + - 4.728982 * y_aux + - 0.791484 * y_aux * x_aux + - 0.1306 * y_aux * Math.pow(x_aux, 2) - - 0.0436 * Math.pow(y_aux, 3); - - // unit 10000" to 1" and seconds to degrees (dec) - lat = (lat * 100) / 36; - lon = (lon * 100) / 36; - - return { lat: lat, lon: lon }; -} - -/** - * Get the gpx trackpoint representation of a Swiss projection coordinate point. - * + * * @param {*} point Array of Swiss projection coordinates, position 0 is E and 1 is N. * @returns Track point xml node for gpx. */ function toTrackPoint(point) { - const wgs84Point = toWGS84(point); - return ``; -} + // convert LV95 into the civilian system + let y_aux = (point[0] - 2600000)/1000000; + let x_aux = (point[1] - 1200000)/1000000; -/** - * Get the gpx waypoint representation of a route portal point. - * - * @returns Way point xml node for gpx. - */ -function toWayPoint(point) { - const wgs84Point = toWGS84(point.geom.coordinates); - return ` - - ${point.altitude} - ${point.display_name} - `; + // calculate longitude and latitude in the unit 10000" + let lat = 16.9023892 + + 3.238272 * x_aux - + 0.270978 * Math.pow(y_aux, 2) - + 0.002528 * Math.pow(x_aux, 2) - + 0.0447 * Math.pow(y_aux, 2) * x_aux - + 0.0140 * Math.pow(x_aux, 3); + + let lng = 2.6779094 + + 4.728982 * y_aux + + 0.791484 * y_aux * x_aux + + 0.1306 * y_aux * Math.pow(x_aux, 2) - + 0.0436 * Math.pow(y_aux, 3); + + // unit 10000" to 1" and seconds to degrees (dec) + lat = lat * 100 / 36; + lng = lng * 100 / 36; + + return ``; } /** * Create track title. - * - * @param {*} geoJson + * + * @param {*} geoJson * @returns Combined route number, id and route title. */ function trackTitle(geoJson) { - const book = geoJson.book_route_number - ? `${geoJson.book_route_number} - ` - : ""; - - return `${book}${geoJson.title}`; + const route = geoJson.segments[0]; + return `${geoJson.book_route_number}-${route.route_id} ${route.title}`; } /** * Create a gpx representation from the sac GeoJSON data. - * - * @param {*} geoJson + * + * @param {*} geoJson * @returns Simple gpx string. */ function toGpx(geoJson) { - const trackSegments = geoJson.segments - .map((segment) => { - if (segment.geom == null) return ""; - return ` - ${segment.geom.coordinates.map(toTrackPoint).join("")} - `; - }) - .join(""); + const route = geoJson.segments[0].geom; + const routeTitle = trackTitle(geoJson); - const departurePoint = geoJson.departure_point - ? toWayPoint(geoJson.departure_point) - : ""; - const endPoint = geoJson.end_point ? toWayPoint(geoJson.end_point) : ""; - const waypoints = geoJson.waypoints - ? geoJson.waypoints - .map((wp) => { - return toWayPoint(wp.reference_poi); - }) - .join("") - : ""; - - const routeTitle = trackTitle(geoJson); - - const xmlString = ` + const xmlString = ` - ${departurePoint} - ${toWayPoint(geoJson.destination_poi)} - ${waypoints} - ${endPoint} Track ${routeTitle} - ${trackSegments} + + ${route.coordinates.map(toTrackPoint).join("")} + `; - const parser = new DOMParser(); - const xmlDoc = parser.parseFromString(xmlString, "text/xml"); + const parser = new DOMParser(); + let xmlDoc = parser.parseFromString(xmlString, "text/xml"); - return new XMLSerializer().serializeToString(xmlDoc.documentElement); + return new XMLSerializer().serializeToString(xmlDoc.documentElement); } /** * Intercept the download of GeoJSON data and save it for the background script. */ function listener(details) { - const filter = browser.webRequest.filterResponseData(details.requestId); - const decoder = new TextDecoder("utf-8"); - const encoder = new TextEncoder(); + let filter = browser.webRequest.filterResponseData(details.requestId); + let decoder = new TextDecoder("utf-8"); + let encoder = new TextEncoder(); - const data = []; - filter.ondata = (event) => { - data.push(event.data); - }; + let data = []; + filter.ondata = event => { + data.push(event.data); + }; - filter.onstop = async (_event) => { - const blob = new Blob(data, { type: "text/html" }); - const buffer = await blob.arrayBuffer(); - const str = decoder.decode(buffer); + filter.onstop = async event => { + let blob = new Blob(data, {type: 'text/html'}); + let buffer = await blob.arrayBuffer(); + let str = decoder.decode(buffer); - updateActiveTab(browser.tabs); + gpxTrack = JSON.parse(str); + updateActiveTab(browser.tabs); - filter.write(encoder.encode(str)); - filter.close(); + filter.write(encoder.encode(str)); + filter.close(); + }; - const geoJson = JSON.parse(str); - const routeTitle = trackTitle(geoJson); - gpxTrack = { title: routeTitle, data: toGpx(geoJson) }; - }; - - return {}; + return {}; } /** * Check if a url should be intercepted. - * - * @param {*} tab + * + * @param {*} tab * @returns True if the active tab is an sac website, false otherwise. */ function checkTrack(tab) { - if (!tab.url) { - return false; - } + if (!tab.url) { + return false; + } - return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack; + return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack; } /** * If a valid tack was selected, download it as a gpx file. */ function handleClick(tab) { - const hasTrack = checkTrack(tab); - if (!hasTrack) { - return; - } + const hasTrack = checkTrack(tab); + if (!hasTrack) { + return; + } - const blob = new Blob([gpxTrack.data], { type: "application/gpx+xml" }); - const objectURL = URL.createObjectURL(blob); + let blob = new Blob([toGpx(gpxTrack)], {type: "application/gpx+xml"}); + let objectURL = URL.createObjectURL(blob); - const downloading = browser.downloads.download({ - url: objectURL, - filename: `${gpxTrack.title}.gpx`, - saveAs: true, - conflictAction: "uniquify", - }); + const routeTitle = trackTitle(gpxTrack); - downloading.then( - (id) => console.log(`Started downloading: ${id}`), - (error) => console.log(`Download failed: ${error}`), - ); - gpxTrack = null; + let downloading = browser.downloads.download({ + url : objectURL, + filename : `track-${routeTitle}.gpx`, + saveAs: true, + conflictAction : 'uniquify' + }); + + downloading.then( + (id) => console.log(`Started downloading: ${id}`), + (error) => console.log(`Download failed: ${error}`)); + gpxTrack = null; } /** * Update the download icon and text. */ -function updateActiveTab(_tabs) { - function updateTab(tabs) { - if (tabs[0]) { - updateIcon(tabs[0]); +function updateActiveTab(tabs) { + function updateTab(tabs) { + if (tabs[0]) { + updateIcon(tabs[0]); + } } - } - - const gettingActiveTab = browser.tabs.query({ - active: true, - currentWindow: true, - }); - gettingActiveTab.then(updateTab); + + let gettingActiveTab = browser.tabs.query({active: true, currentWindow: true}); + gettingActiveTab.then(updateTab); } /** * Update the download icon. */ function updateIcon(tab) { - const hasTrack = checkTrack(tab); + const hasTrack = checkTrack(tab); - browser.browserAction.setIcon({ - path: hasTrack - ? { + browser.browserAction.setIcon({ + path: hasTrack ? { 48: "icons/map.png", - } - : { + } : { 48: "icons/map-disabled.png", }, - tabId: tab.id, - }); - browser.browserAction.setTitle({ - title: hasTrack - ? `Download track "${gpxTrack.title}"` - : "No track selected", - tabId: tab.id, - }); + tabId: tab.id + }); + browser.browserAction.setTitle({ + title: hasTrack ? `Download track ${trackTitle(gpxTrack)}` : 'No track selected', + tabId: tab.id + }); } browser.webRequest.onBeforeRequest.addListener( - listener, - { urls: ["https://www.sac-cas.ch/*[routeId]*"] }, - ["blocking"], + listener, + {urls: ["https://www.sac-cas.ch/*[routeId]*"]}, + ["blocking"] ); browser.browserAction.onClicked.addListener(handleClick); @@ -257,5 +198,5 @@ browser.browserAction.onClicked.addListener(handleClick); browser.tabs.onUpdated.addListener(updateActiveTab); browser.tabs.onActivated.addListener(updateActiveTab); browser.windows.onFocusChanged.addListener(updateActiveTab); - + updateActiveTab(); diff --git a/manifest.json b/manifest.json index 8c464a2..7448734 100644 --- a/manifest.json +++ b/manifest.json @@ -1,15 +1,19 @@ { + "manifest_version": 2, - "name": "SAC Route Portal GPX Downloader", - "version": "0.8", + "name": "SAC Route Portal GPX", + "version": "0.1", "developer": { "name": "Sebastian Hugentobler", "url": "https://code.vanwa.ch/sebastian/sac-route-portal-gpx-fx" }, + "description": "Download gpx tracks from the sac route portal.", + "icons": { "48": "icons/map.png" }, + "permissions": [ "activeTab", "downloads", @@ -17,13 +21,13 @@ "webRequestBlocking", "https://www.sac-cas.ch/*" ], + "background": { - "scripts": [ - "background.js" - ] + "scripts": ["background.js"] }, + "browser_action": { "default_icon": "icons/map.png", "default_title": "To GPX" - } + } }