Gaia Updater fix (new Gaia GPS upload process)

This commit is contained in:
2020-12-28 19:34:41 +01:00
parent af5b438d64
commit 6180a04782

View File

@@ -1,11 +1,14 @@
// ==UserScript==
// @name GaiaGps Uploader v2
// @version 2.0
// @grant none
// @match https://www.gaiagps.com/upload/
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.0/jquery.min.js
// @name GaiaGps Uploader
// @version 3.0
// @grant none
// @match https://www.gaiagps.com/map/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.0/jquery.min.js
// @namespace https://greasyfork.org/users/583371
// ==/UserScript==
//Ctrl+Alt+Shift+I to open network tab on addon
var gpxParser = function () {
this.xmlSource = "";
this.metadata = {};
@@ -151,7 +154,7 @@ gpxParser.prototype.parse = function (gpxstring) {
gpxParser.prototype.getElementValue = function(parent, needle){
let elem = parent.querySelector(needle);
if(elem != null){
return elem.innerHTML != undefined ? elem.innerHTML : elem.childNodes[0].data;
return $('<div>').html(elem.innerHTML != undefined ? elem.innerHTML : elem.childNodes[0].data).text();
}
return elem;
}
@@ -175,6 +178,117 @@ gpxParser.prototype.queryDirectSelector = function(parent, needle) {
return finalElem;
}
/*
gpxParser.prototype.toGeoJSON = function () {
var GeoJSON = {
"type": "FeatureCollection",
"features": [],
"properties": {
"name": this.metadata.name,
"desc": this.metadata.desc,
"time": this.metadata.time,
"author": this.metadata.author,
"link": this.metadata.link,
},
};
for(idx in this.tracks) {
let track = this.tracks[idx];
var feature = {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": []
},
"properties": {
}
};
feature.properties.name = track.name;
feature.properties.cmt = track.cmt;
feature.properties.desc = track.desc;
feature.properties.src = track.src;
feature.properties.number = track.number;
feature.properties.link = track.link;
feature.properties.type = track.type;
for(idx in track.points) {
let pt = track.points[idx];
var geoPt = [];
geoPt.push(pt.lon);
geoPt.push(pt.lat);
geoPt.push(pt.ele);
feature.geometry.coordinates.push(geoPt);
}
GeoJSON.features.push(feature);
}
for(idx in this.routes) {
let track = this.routes[idx];
var feature = {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": []
},
"properties": {
}
};
feature.properties.name = track.name;
feature.properties.cmt = track.cmt;
feature.properties.desc = track.desc;
feature.properties.src = track.src;
feature.properties.number = track.number;
feature.properties.link = track.link;
feature.properties.type = track.type;
for(idx in track.points) {
let pt = track.points[idx];
var geoPt = [];
geoPt.push(pt.lon);
geoPt.push(pt.lat);
geoPt.push(pt.ele);
feature.geometry.coordinates.push(geoPt);
}
GeoJSON.features.push(feature);
}
for(idx in this.waypoints) {
let pt = this.waypoints[idx];
var feature = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": []
},
"properties": {
}
};
feature.properties.name = pt.name;
feature.properties.cmt = pt.cmt;
feature.properties.desc = pt.desc;
feature.geometry.coordinates = [pt.lon, pt.lat, pt.ele];
GeoJSON.features.push(feature);
}
return GeoJSON;
}
*/
gpxParser.prototype.getGPX = function(sName) {
var sTrack = '';
@@ -206,21 +320,30 @@ class Gaia {
static get URL() { return 'https://www.gaiagps.com'; }
static get API() { return Gaia.URL+'/api/objects'; }
constructor($Form) {
constructor($InputFile, $InputButton) {
this.asFiles = [];
this.aoWaypoints = [];
this.aoTracks = [];
this.sFolderId = '';
this.asFolder = {};
this.sFolderName = '';
this.$Feedback = $('<div>', {'style':'position:fixed;width:100%;height:25%;bottom:0;background:white;z-index:10000;border-top:1px solid #CCC;box-sizing:border-box;font-size:1.2em;overflow:auto;padding:0 1em;'});
this.$InputName = $('<input>', {'type':'text', 'name':'folder_name', 'placeholder':'Folder Name', 'style': 'border-width:2px; border-color:rgba(0, 0, 0, 0.1); border-radius:4px; font-family:Inter,Helvetica Neue,Helvetica,Arial; font-size:15px; padding:8px 12px; margin-bottom:12px;'});
this.$InputBox = $InputButton.parent();
//Reboot object to remove events
this.$InputFile = $InputFile.clone().insertAfter($InputFile);
$InputFile.remove();
this.$InputButton = $InputButton.clone().insertAfter($InputButton);
$InputButton.remove();
this.$Form = $Form;
this.$InputName = $Form.find('input[name=name]');
this.$InputFile = $Form.find('input[type=file]');
this.$Feedback = $Form.after($('<div>'));
this.setLayout();
}
feedback(sType, sMsg) {
var sFormattedMsg = sType.charAt(0).toUpperCase()+sType.slice(1)+': '+sMsg+'.';
var sFormattedMsg = sType.charAt(0).toUpperCase()+sType.slice(1)+': '+sMsg+(sMsg.slice(-1)=='.'?'':'.');
console.log(sFormattedMsg);
let sColor = 'black';
@@ -230,97 +353,29 @@ class Gaia {
case 'info': sColor = 'green'; break;
}
this.$Feedback.append($('<p>', {'style': 'color: '+sColor+';'}).text(sFormattedMsg));
this.$Feedback.scrollTop(this.$Feedback.prop("scrollHeight"));
}
//Modify Gaia DOM Interface
setLayout() {
//Add Feedback box
this.$Feedback.appendTo($('body'));
//Add Event on button
this.$InputButton.click(() => {this.$InputFile.click();});
//Set event on file selection
this.$InputFile
.attr('multiple', 'multiple')
.attr('name', 'files[]')
.change(() => {this.readInputFiles();});
//Remove submit button & edit label
this.$Form.find('#fileuploadtext').text('Select files');
this.$Form.find('button[type=submit]').hide();
//Set default Name
this.$InputName.val('PCT');
this.$InputName.val('PCT').prependTo(this.$InputBox);
//Clear all upload notifications
this.resetNotif();
}
//Parse files from input (multiple)
readInputFiles() {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
this.feedback('error', 'File APIs are not fully supported in this browser');
return;
}
else this.feedback('info', 'Parsing input files');
//Get Folder Name (text input)
this.sFolderName = this.$InputName.val();
let aoReaders = [];
let asFiles = this.$InputFile.prop('files');
let asContents = [];
for(var i=0 ; i < asFiles.length ; i++) {
aoReaders[i] = new FileReader();
aoReaders[i].onload = ((asResult) => {
asContents.push(asResult.target.result);
this.feedback('info', 'Reading file '+asContents.length+'/'+asFiles.length);
if(asContents.length == asFiles.length) this.parseFile(asContents);
});
aoReaders[i].readAsText(asFiles[i]);
}
}
//Parse GPX files to consolidate tracks & waypoints
parseFile(asContents) {
this.feedback('info', 'Merging files');
for(var i in asContents) {
var oGPX = new gpxParser();
oGPX.parse(asContents[i]);
//Waypoints
for(var w in oGPX.waypoints) {
var sWaypointName = oGPX.waypoints[w].name;
if(sWaypointName.indexOf('Milestone - ') != -1 && sWaypointName.substr(-2) != '00') { //1 milestone every 100 miles
this.feedback('info', 'Ignoring milestone waypoint "'+sWaypointName+'"');
}
else this.aoWaypoints.push(oGPX.waypoints[w]);
}
//Tracks
for(var t in oGPX.tracks) {
this.aoTracks.push(oGPX.tracks[t]);
}
}
this.deleteFolder();
}
//Delete existing folder with same name
deleteFolder() {
this.feedback('info', 'Looking for existing "'+this.sFolderName+'" folder...');
$.get(Gaia.API+'/folder/?routepoints=false&show_archived=true&show_filed=true').done((asFolders) => {
var bCalled = false;
for(var f in asFolders) {
if(asFolders[f].title == this.sFolderName) {
bCalled = true;
this.feedback('info', 'Deleting "'+this.sFolderName+'" folder');
$.ajax({
url: Gaia.API+'/folder/'+asFolders[f].id+'/',
type: 'DELETE'
});
}
}
if(!bCalled) this.feedback('info', 'No folder named "'+this.sFolderName+'" found');
this.uploadTrack();
});
//Clear all upload notifications
this.resetNotif();
}
//Marking all upload notifications as read
@@ -335,8 +390,170 @@ class Gaia {
});
}
//Parse files from input (multiple)
readInputFiles() {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
this.feedback('error', 'File APIs are not fully supported in this browser');
return;
}
else this.feedback('info', 'Parsing input files');
//Get Folder Name (text input)
this.sFolderName = this.$InputName.val();
let aoReaders = [];
let iCount = 0;
this.asFiles = this.$InputFile.prop('files');
for(var i=0 ; i < this.asFiles.length ; i++) {
aoReaders[i] = new FileReader();
aoReaders[i].onload = ((oFileReader) => {
return (asResult) => {
iCount++;
this.feedback('info', 'Reading file "'+oFileReader.name+'" ('+iCount+'/'+this.asFiles.length+')');
this.parseFile(oFileReader.name, asResult.target.result);
if(iCount == this.asFiles.length) this.createFolder();
};
})(this.asFiles[i]);
aoReaders[i].readAsText(this.asFiles[i]);
}
}
//Parse GPX files to consolidate tracks & waypoints
parseFile(sFileName, oContent) {
this.feedback('info', 'Parsing file "'+sFileName+'"');
var oGPX = new gpxParser();
oGPX.parse(oContent);
//Waypoints
for(var w in oGPX.waypoints) {
oGPX.waypoints[w].filename = sFileName;
var sWaypointName = oGPX.waypoints[w].name;
if(sWaypointName.indexOf('Milestone - ') != -1 && sWaypointName.substr(-2) != '00') { //1 milestone every 100 miles
this.feedback('info', 'Ignoring milestone waypoint "'+sWaypointName+'"');
}
else this.aoWaypoints.push(oGPX.waypoints[w]);
}
//Tracks
for(var t in oGPX.tracks) {
oGPX.tracks[t].filename = sFileName;
this.aoTracks.push(oGPX.tracks[t]);
}
}
//Delete existing folder with same name & recreating it
createFolder() {
this.feedback('info', 'Looking for existing folder "'+this.sFolderName+'"...');
$.get(Gaia.API+'/folder/?search='+this.sFolderName).done((asFolders) => {
if(asFolders != '' && !$.isEmptyObject(asFolders)) {
for(var f in asFolders) {
this.feedback('info', 'Deleting "'+asFolders[f].title+'" folder');
$.ajax({
url: Gaia.API+'/folder/'+asFolders[f].id+'/',
type: 'DELETE'
});
}
}
else this.feedback('info', 'No folder named "'+this.sFolderName+'" found');
this.feedback('info', 'Creating folder "'+this.sFolderName+'"');
$.post({
url: Gaia.API+'/folder/',
contentType: 'application/json',
data: JSON.stringify({imported: true, title: this.sFolderName})
}).done((asFolder) => {
this.feedback('info', 'Folder "'+asFolder.properties.name+'" created');
this.asFolder = asFolder;
this.sFolderId = asFolder.id;
this.sFolderName = asFolder.properties.name;
this.uploadTrack();
});
});
}
//Build & Upload Track File
uploadTrack() {
this.feedback('info', 'Uploading tracks...');
//Convert to geojson
let iPostedTracks = 0;
$.each(this.aoTracks, (iIndex, aoTrack) => {
//Set color
let sColor = '#4ABD32';
switch(aoTrack.color) {
case 'DarkBlue': sColor = '#2D3FC7'; break;
case 'Magenta': sColor = '#B60DC3'; break;
}
//Add track points
let aoCoords = [];
for(var p in aoTrack.points) {
let pt = aoTrack.points[p];
aoCoords.push([pt.lon, pt.lat, pt.ele, 0]);
}
//Upload
let sPostedData = JSON.stringify({
type: 'feature',
properties: {
color: sColor,
title: aoTrack.name,
time_created: '2020-12-27T11:34:03.537Z',
routing_mode: null,
notes: aoTrack.desc,
//distance: 168405.62350073704,
isValid: true,
isLatestImport: true,
filename: aoTrack.filename,
localId: 'track'+(iIndex + 1),
writable: true,
archived: false,
isPublicTrack: false,
isLocallyCreated: true,
type: 'track',
parent_folder_id: this.sFolderId,
hexcolor: sColor
},
geometry: {
type: 'MultiLineString',
coordinates: [aoCoords]
}
});
var self = this;
this.feedback('info', 'Uploading track "'+aoTrack.name+'"');
$.post({
url: Gaia.API+'/track/',
contentType: 'application/json',
data: sPostedData,
postedData: sPostedData,
trackName: aoTrack.name
}).done(function(asTrack) {
self.aoTracks[iIndex] = asTrack;
$.ajax({
url: Gaia.API+'/track/'+asTrack.features[0].id+'/',
type: 'PUT',
contentType: 'application/json',
data: this.postedData,
trackName: this.trackName
}).done(function() {
iPostedTracks++;
self.feedback('info', 'Track "'+this.trackName+'" uploaded');
if(iPostedTracks == self.aoTracks.length) {
self.feedback('info', 'All tracks uploaded');
self.uploadWayPoints();
}
}).fail(function() {
self.feedback('error', 'Track "'+this.trackName+'" failed to upload');
});
});
});
/* Legacy lethod: through form submit
//Build track file
this.feedback('info', 'Building consolidated track');
var oGPX = new gpxParser();
@@ -358,8 +575,10 @@ class Gaia {
contentType: false,
cache: false
}).done(() => {this.checkNotif();});
*/
}
/*
//Wait for file to be processed by Gaia
checkNotif() {
this.feedback('info', 'Waiting for Gaia to process consolidated track');
@@ -424,6 +643,7 @@ class Gaia {
}
});
}
*/
uploadWayPoints(iIndex, bSecondTry) {
iIndex = iIndex || 0;
@@ -433,7 +653,7 @@ class Gaia {
if(iIndex < this.aoWaypoints.length) {
var sWaypointName = this.aoWaypoints[iIndex].name;
this.feedback('info', 'Waypoints Upload - Uploading waypoint '+(iIndex + 1)+'/'+this.aoWaypoints.length+' ('+sWaypointName+')');
this.feedback('info', 'Uploading waypoint '+(iIndex + 1)+'/'+this.aoWaypoints.length+' ('+sWaypointName+')');
var asPost = {
type: 'Feature',
geometry: {
@@ -448,61 +668,77 @@ class Gaia {
title: sWaypointName,
time_created: "2020-06-07T14:01:03.944Z",
icon: Gaia.getIconName(this.aoWaypoints[iIndex].sym),
writable: true,
localId: iIndex+'',
archived: false,
isTitleLoaded: true,
isLocallyCreated: true,
type: 'waypoint'
isValid: true,
isLatestImport: true,
filename: this.aoWaypoints[iIndex].filename,
writable: true,
localId: iIndex+'',
notes: this.aoWaypoints[iIndex].desc,
archived: false,
isLocallyCreated: true,
type: 'waypoint',
parent_folder_id: this.sFolderId
}
};
if(this.aoWaypoints[iIndex].desc) asPost.properties.notes = this.aoWaypoints[iIndex].desc;
$.ajax({
let sData = JSON.stringify(asPost);
var self = this;
$.post({
url: Gaia.API+'/waypoint/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(asPost)
}).done((asWaypoint) => {
data: sData,
postedData: sData
}).done(function(asWaypoint) {
//Update local waypoint with all server info (including ID)
this.aoWaypoints[iIndex] = asWaypoint;
self.aoWaypoints[iIndex] = asWaypoint;
$.get(Gaia.URL+'/public/generate?type=waypoint&objectid='+asWaypoint.properties.id).always(() => {
this.uploadWayPoints(++iIndex);
$.ajax({
url: Gaia.API+'/waypoint/'+asWaypoint.properties.id+'/',
type: 'PUT',
contentType: 'application/json',
data: this.postedData
}).always(() => {
self.uploadWayPoints(++iIndex);
});
}).fail(function(){
this.feedback('error', 'Waypoints Upload - Failed to upload waypoint #'+(iIndex + 1)+' ('+sWaypointName+'). Trying again...');
this.uploadWayPoints(iIndex, true);
self.feedback('error', 'Failed to upload waypoint #'+(iIndex + 1)+' ('+sWaypointName+'). Trying again...');
self.uploadWayPoints(iIndex, true);
});
}
//Done uploading, assigning waypoints to folder
else {
this.feedback('info', 'Waypoints Upload - Getting folders list');
$.get(Gaia.API+'/folder/').done((asFolders) => {
//Find Folder
for(var f in asFolders) {
if(asFolders[f].id == this.sFolderId) {
var asFolder = asFolders[f];
}
}
//Done uploading, assigning waypoints & tracks to folder
else this.assignElementsToFolder();
}
//Assign waypoints to folder
for(var i in this.aoWaypoints) asFolder.waypoints.push(this.aoWaypoints[i].properties.id);
assignElementsToFolder() {
this.feedback('info', 'Assigning all elements to folder "'+this.asFolder.properties.name+'"');
this.feedback('info', 'Waypoints Upload - Assigning waypoints to folder '+this.sFolderId);
$.ajax({
url: Gaia.API+'/folder/'+this.sFolderId+'/',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(asFolder)
}).done(() => {
this.feedback('info', 'Waypoints Upload - Finished successfully');
}).fail(() => {
this.feedback('error', 'Waypoints Upload - Failed to assign waypoints to folder "'+sFolderId+'"');
});
});
let asFolder = {
cover_photo_id: this.asFolder.properties.cover_photo_id,
id: this.asFolder.id,
name: this.asFolder.properties.name,
notes: this.asFolder.properties.notes,
time_created: this.asFolder.properties.time_created,
updated_date: this.asFolder.properties.updated_date
}
//Assign waypoints to folder
asFolder.waypoints = [];
for(var w in this.aoWaypoints) asFolder.waypoints.push(this.aoWaypoints[w].properties.id);
//Assign tracks to folder
asFolder.tracks = [];
for(var t in this.aoTracks) asFolder.tracks.push(this.aoTracks[t].features[0].id);
$.ajax({
url: Gaia.API+'/folder/'+asFolder.id+'/',
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(asFolder)
}).done(() => {
this.feedback('info', 'Done');
}).fail(() => {
this.feedback('error', 'WFailed to assign waypoints & tracks to folder ID "'+asFolder.id+'"');
});
}
static getIconName(sGarminName) {
@@ -540,6 +776,10 @@ class Gaia {
}
}
console.log('computes');
console.log('Loading GaiaGps Uploader...');
let oGaia = new Gaia($('#uploadForm'));
//To be adjusted regularly
$FileInput = $('input[type=file]')
$FileButton = $('a[href="https://help.gaiagps.com/hc/en-us/articles/360052763513"]').parent().find('button');
let oGaia = new Gaia($FileInput, $FileButton);