Sanitize filenames of downloads.
Some routes have characters like ":" in them which can be illegal on certain filesystems. Remove the known common ones and replace them with an underscore.
This commit is contained in:
parent
59d0f01f87
commit
6e91a15ca7
21
README.md
21
README.md
@ -1,23 +1,28 @@
|
|||||||
# SAC Route Portal GPX Downloader
|
# SAC Route Portal GPX Downloader
|
||||||
|
|
||||||
The [Swiss Alpine Club](https://www.sac-cas.ch/en/) has a great
|
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/)
|
[route portal](https://www.sac-cas.ch/en/huts-and-tours/sac-route-portal/) for
|
||||||
for finding interesting hiking routes.
|
finding interesting hiking routes.
|
||||||
|
|
||||||
However you can not download the tracks as gpx files, as they argue that the exact
|
However you can not download the tracks as gpx files, as they argue that the
|
||||||
paths are subject to change and it could be dangerous to adhere too closely to them.
|
exact paths are subject to change and it could be dangerous to adhere too
|
||||||
|
closely to them.
|
||||||
|
|
||||||
I do agree with that, but you can draw your own routes
|
I do agree with that, but you can draw your own routes and download those,
|
||||||
and download those, mainly taking some time to draw after the route they are
|
mainly taking some time to draw after the route they are already showing on the
|
||||||
already showing on the map.
|
map.
|
||||||
|
|
||||||
With this extension you can select any track and then download it as a gpx file
|
With this extension you can select any track and then download it as a gpx file
|
||||||
(an active subscription is needed).
|
(an active subscription is needed).
|
||||||
|
|
||||||
## Be Cautious!
|
## Be Cautious!
|
||||||
|
|
||||||
Heed their warning and do not blindly follow the gps track! Use your brain and
|
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.
|
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/).
|
Take a look at their
|
||||||
|
[safety instructions](https://www.sac-cas.ch/en/training-and-safety/safety/).
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
- wizche
|
- wizche
|
||||||
|
@ -21,14 +21,16 @@ function toWGS84(point) {
|
|||||||
const x_aux = (point[1] - 1200000) / 1000000;
|
const x_aux = (point[1] - 1200000) / 1000000;
|
||||||
|
|
||||||
// calculate longitude and latitude in the unit 10000"
|
// calculate longitude and latitude in the unit 10000"
|
||||||
let lat = 16.9023892 +
|
let lat =
|
||||||
|
16.9023892 +
|
||||||
3.238272 * x_aux -
|
3.238272 * x_aux -
|
||||||
0.270978 * Math.pow(y_aux, 2) -
|
0.270978 * Math.pow(y_aux, 2) -
|
||||||
0.002528 * Math.pow(x_aux, 2) -
|
0.002528 * Math.pow(x_aux, 2) -
|
||||||
0.0447 * Math.pow(y_aux, 2) * x_aux -
|
0.0447 * Math.pow(y_aux, 2) * x_aux -
|
||||||
0.014 * Math.pow(x_aux, 3);
|
0.014 * Math.pow(x_aux, 3);
|
||||||
|
|
||||||
let lon = 2.6779094 +
|
let lon =
|
||||||
|
2.6779094 +
|
||||||
4.728982 * y_aux +
|
4.728982 * y_aux +
|
||||||
0.791484 * y_aux * x_aux +
|
0.791484 * y_aux * x_aux +
|
||||||
0.1306 * y_aux * Math.pow(x_aux, 2) -
|
0.1306 * y_aux * Math.pow(x_aux, 2) -
|
||||||
@ -102,10 +104,10 @@ function toGpx(geoJson) {
|
|||||||
const endPoint = geoJson.end_point ? toWayPoint(geoJson.end_point) : "";
|
const endPoint = geoJson.end_point ? toWayPoint(geoJson.end_point) : "";
|
||||||
const waypoints = geoJson.waypoints
|
const waypoints = geoJson.waypoints
|
||||||
? geoJson.waypoints
|
? geoJson.waypoints
|
||||||
.map((wp) => {
|
.map((wp) => {
|
||||||
return toWayPoint(wp.reference_poi);
|
return toWayPoint(wp.reference_poi);
|
||||||
})
|
})
|
||||||
.join("")
|
.join("")
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const routeTitle = trackTitle(geoJson);
|
const routeTitle = trackTitle(geoJson);
|
||||||
@ -179,6 +181,41 @@ function checkTrack(tab) {
|
|||||||
return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack;
|
return tab.url.match("https://www.sac-cas.ch/.*") && gpxTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove characters that lead to problems in common filesystems.
|
||||||
|
*
|
||||||
|
* Windows (NTFS) seems to have the most restrictions, so it is mostly sourced from there.
|
||||||
|
*
|
||||||
|
* Reserved names on windows: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
|
||||||
|
*
|
||||||
|
* Code comes from https://github.com/parshap/node-sanitize-filename/blob/master/index.js
|
||||||
|
*/
|
||||||
|
function sanitizeFilename(input) {
|
||||||
|
const illegal = /[\/\?<>\\:\*\|"]/g;
|
||||||
|
// deno-lint-ignore no-control-regex
|
||||||
|
const control = /[\x00-\x1f\x80-\x9f]/g;
|
||||||
|
const reserved = /^\.+$/;
|
||||||
|
const windowsReserved = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
||||||
|
const windowsTrailing = /[\. ]+$/;
|
||||||
|
const replacement = "_";
|
||||||
|
|
||||||
|
const sanitized = input
|
||||||
|
.replace(illegal, replacement)
|
||||||
|
.replace(control, replacement)
|
||||||
|
.replace(reserved, replacement)
|
||||||
|
.replace(windowsReserved, replacement)
|
||||||
|
.replace(windowsTrailing, replacement);
|
||||||
|
|
||||||
|
if (sanitized.length === 0) {
|
||||||
|
sanitized = "unnamed";
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLength = 250;
|
||||||
|
const uint8Array = new TextEncoder().encode(sanitized);
|
||||||
|
const truncated = uint8Array.slice(0, maxLength);
|
||||||
|
return new TextDecoder().decode(truncated);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a valid tack was selected, download it as a gpx file.
|
* If a valid tack was selected, download it as a gpx file.
|
||||||
*/
|
*/
|
||||||
@ -191,9 +228,10 @@ function handleClick(tab) {
|
|||||||
const blob = new Blob([gpxTrack.data], { type: "application/gpx+xml" });
|
const blob = new Blob([gpxTrack.data], { type: "application/gpx+xml" });
|
||||||
const objectURL = URL.createObjectURL(blob);
|
const objectURL = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const filename = sanitizeFilename(gpxTrack.title);
|
||||||
const downloading = browser.downloads.download({
|
const downloading = browser.downloads.download({
|
||||||
url: objectURL,
|
url: objectURL,
|
||||||
filename: `${gpxTrack.title}.gpx`,
|
filename: `${filename}.gpx`,
|
||||||
saveAs: true,
|
saveAs: true,
|
||||||
conflictAction: "uniquify",
|
conflictAction: "uniquify",
|
||||||
});
|
});
|
||||||
@ -231,11 +269,11 @@ function updateIcon(tab) {
|
|||||||
browser.browserAction.setIcon({
|
browser.browserAction.setIcon({
|
||||||
path: hasTrack
|
path: hasTrack
|
||||||
? {
|
? {
|
||||||
48: "icons/map.png",
|
48: "icons/map.png",
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
48: "icons/map-disabled.png",
|
48: "icons/map-disabled.png",
|
||||||
},
|
},
|
||||||
tabId: tab.id,
|
tabId: tab.id,
|
||||||
});
|
});
|
||||||
browser.browserAction.setTitle({
|
browser.browserAction.setTitle({
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "SAC Route Portal GPX Downloader",
|
"name": "SAC Route Portal GPX Downloader",
|
||||||
"version": "0.8",
|
"version": "0.9",
|
||||||
"developer": {
|
"developer": {
|
||||||
"name": "Sebastian Hugentobler",
|
"name": "Sebastian Hugentobler",
|
||||||
"url": "https://code.vanwa.ch/sebastian/sac-route-portal-gpx-fx"
|
"url": "https://code.vanwa.ch/sebastian/sac-route-portal-gpx-fx"
|
||||||
|
Loading…
Reference in New Issue
Block a user