فهرست منبع

Initial commit

Florian 1 سال پیش
والد
کامیت
a84e8722bb
5فایلهای تغییر یافته به همراه314 افزوده شده و 1 حذف شده
  1. 1 1
      .gitignore
  2. 56 0
      README.md
  3. 195 0
      main.js
  4. 46 0
      package-lock.json
  5. 16 0
      package.json

+ 1 - 1
.gitignore

@@ -1,5 +1,5 @@
 # ---> NetBeans
-nbproject/private/
+nbproject/
 build/
 nbbuild/
 dist/

+ 56 - 0
README.md

@@ -1,2 +1,58 @@
 # PhoneTrackGPXFix
 
+A nodejs app that puts in time order gps points exported from PhoneTrack in NextCloud so that they can be correctly imported in JOSM.
+
+Disclaimer: This project has been done in an hour or so. So please expect bugs, dirty code and odd behaviour that look more like a one-hour side-project. Also this has only been tested on Windows.
+
+## How to install
+
+Download [nodejs]([Download | Node.js](https://nodejs.org/en/download)) and [git]([Git - Downloads](https://git-scm.com/downloads)).
+
+Open your favorite shell and execute (windows or linux):
+
+```bash
+git clone https://floriananaya.pro/git/florian/PhoneTrackGPXFix
+cd PhoneTrackGPXFix
+npm install
+```
+
+## How to use
+
+The only command is
+
+```bash
+node main.js <FilePath>
+```
+
+## Example
+
+```bash
+node main.js C:\Users\Florian\Downloads\florian1.gpx
+```
+
+Expected output:
+
+```Bash
+C:\Users\Florian\Downloads\PhoneTrackGPXFix>node main.js C:\Users\Florian\Downloads\florian1.gpx
+Started PhoneTrack GPX file fixer
+Reading file located at "C:\Users\Florian\Downloads\florian1.gpx"...
+File has been read, loading XML...
+XML has been loaded, reading PhoneTrack data...
+Loading track "ONEPLUSA5000" with 157457 points
+Done loading track "ONEPLUSA5000"
+Loading track "OPPO" with 27814 points
+Done loading track "OPPO"
+Sorting all points...
+Sorting points...
+Done reading and sorting track "ONEPLUSA5000"
+Sorting points...
+Done reading and sorting track "OPPO"
+Done sorting all points
+Updating XML...
+Done updating XML
+Writing to new file "C:\Users\Florian\Downloads\florian1.gpx2"
+Data written to file
+Done in 6.121 sec
+```
+
+The given file stays untouched, a new file will be created that has the same name as the given file with a "2" added at the end of the file (example: "export.gpx" will be renamed to "export.gpx2")

+ 195 - 0
main.js

@@ -0,0 +1,195 @@
+/* global process */
+
+/*
+ * A nodejs app that puts in time order gps points exported from PhoneTrack in NextCloud
+ * so that they can be correctly imported in JOSM
+ * 
+ * author: Florian ANAYA
+ * date: 2023/08/31
+ */
+
+const fileSystemLib = require('fs');
+const xmlJsLib = require('xml-js');
+
+// @type String The path of the file to read
+var filePath;
+// @type Array[Track] List of tracks read from the file
+const tracks = [];
+// @type Date The starting time of the script so that we can calculate the ellapsed time at the end of the script
+var startTime;
+
+
+function main()
+{
+    startTime = new Date();
+    console.log("Started PhoneTrack GPX file fixer");
+    if (process.argv.length <= 2)
+    {
+        console.log("Please specify file path");
+        return;
+    }
+    filePath = process.argv[2];
+    console.log("Reading file located at \"" + filePath + "\"...");
+    
+    // We read the file
+    fileSystemLib.readFile(filePath, onFileRead);
+}
+
+function onFileRead(error, fileData)
+{
+    if (error)
+    {
+        throw error;
+    }
+    // We read XML dazta from the file (this will throw if the file is not XML)
+    console.log("File has been read, loading XML...");
+    let xmlData = xmlJsLib.xml2js(fileData);
+    console.log("XML has been loaded, reading PhoneTrack data...");
+    
+    
+    let rootElements = xmlData.elements;
+    let gpxData = rootElements[0];
+    let gpxElements = gpxData.elements;
+    
+    for (let index in gpxElements)
+    {
+        let gpxChildData = gpxElements[index];
+        if (gpxChildData.name === "trk")
+        {
+            loadTrack(gpxChildData);
+        }
+    }
+    sortTracks();
+    updateXml(xmlData);
+}
+
+
+function loadTrack(trackData)
+{
+    let track = new Track(trackData);
+    tracks.push(track);
+}
+
+function sortTracks()
+{
+    console.log("Sorting all points...");
+    for (let index in tracks)
+    {
+        let track = tracks[index];
+        track.sort();
+    }
+    console.log("Done sorting all points");
+};
+
+function updateXml(xmlData)
+{
+    console.log("Updating XML...");
+    for (let index in tracks)
+    {
+        let track = tracks[index];
+        track.sortXml();
+    }
+    console.log("Done updating XML");
+    let newFilePath = filePath + "2";
+    console.log("Writing to new file \"" + newFilePath + "\"");
+    
+    let xmlBack = xmlJsLib.js2xml(xmlData, {spaces: 2, indentCdata: true});
+    fileSystemLib.writeFile(newFilePath, xmlBack, function(error, data)
+    {
+        if (error)
+        {
+            throw error;
+        }
+        console.log("Data written to file");
+        let endTime = new Date();
+        let timeDiff = (endTime - startTime) / 1000; //in sec
+        console.log("Done in " + timeDiff + " sec");
+    });
+};
+
+
+
+
+
+
+
+function Track(trackData)
+{
+    this.m_points = [];
+    
+    let elementsData = trackData.elements;
+    for (let index in elementsData)
+    {
+        let elementData = elementsData[index];
+        if (elementData.name === "name")
+        {
+            this.m_trackName = elementData.elements[0].text;
+        }
+        else if (elementData.name === "trkseg")
+        {
+            this.m_pointsData = elementData.elements;
+        }
+    }
+    console.log("Loading track \"" + this.m_trackName + "\" with " + this.m_pointsData.length + " points");
+    
+    for (let index in this.m_pointsData)
+    {
+        let pointData = this.m_pointsData[index];
+        let point = new Point(pointData);
+        this.m_points.push(point);
+    }
+    console.log("Done loading track \"" + this.m_trackName + "\"");
+}
+Track.prototype.m_name;
+// @type Array[Point]
+Track.prototype.m_points;
+
+Track.prototype.sort = function()
+{
+    console.log("Sorting points...");
+    this.m_points.sort(function(pointA, pointB)
+    {
+        return pointA.getTimestamp() - pointB.getTimestamp();
+    });
+    console.log("Done reading and sorting track \"" + this.m_trackName + "\"");
+};
+
+Track.prototype.sortXml = function()
+{
+    // We empty the original array of points data (we don't use this.m_pointsData=[] because we want to update the original array instead of creating a new one)
+    this.m_pointsData.splice(0, this.m_pointsData.length);
+    for (let index in this.m_points)
+    {
+        let point = this.m_points[index];
+        this.m_pointsData.push(point.getData());
+    }
+};
+
+
+
+
+
+
+
+function Point(pointData)
+{
+    this.m_data = pointData;
+    this.m_timestamp = new Date(this.m_data.elements[0].elements[0].text).getTime();
+}
+Point.prototype.m_data;
+Point.prototype.m_timestamp;
+
+Point.prototype.getData = function()
+{
+    return this.m_data;
+};
+
+Point.prototype.getTimestamp = function()
+{
+    return this.m_timestamp;
+};
+
+
+
+// Execution of the script
+main();

+ 46 - 0
package-lock.json

@@ -0,0 +1,46 @@
+{
+    "name": "PhoneTrackGPXFix",
+    "version": "1.0.0",
+    "lockfileVersion": 2,
+    "requires": true,
+    "packages": {
+        "": {
+            "name": "PhoneTrackGPXFix",
+            "version": "1.0.0",
+            "dependencies": {
+                "xml-js": "^1.6.11"
+            }
+        },
+        "node_modules/sax": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+        },
+        "node_modules/xml-js": {
+            "version": "1.6.11",
+            "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+            "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+            "dependencies": {
+                "sax": "^1.2.4"
+            },
+            "bin": {
+                "xml-js": "bin/cli.js"
+            }
+        }
+    },
+    "dependencies": {
+        "sax": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+            "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+        },
+        "xml-js": {
+            "version": "1.6.11",
+            "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+            "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+            "requires": {
+                "sax": "^1.2.4"
+            }
+        }
+    }
+}

+ 16 - 0
package.json

@@ -0,0 +1,16 @@
+{
+    "name": "PhoneTrackGPXFix",
+    "version": "1.0.0",
+    "keywords": [
+        "util",
+        "functional",
+        "server",
+        "client",
+        "browser"
+    ],
+    "author": "Florian",
+    "contributors": [],
+    "dependencies": {
+        "xml-js": "^1.6.11"
+    }
+}