main.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /* global process */
  2. /*
  3. * A nodejs app that puts in time order gps points exported from PhoneTrack in NextCloud
  4. * so that they can be correctly imported in JOSM
  5. *
  6. * author: Florian ANAYA
  7. * date: 2023/08/31
  8. */
  9. const fileSystemLib = require('fs');
  10. const xmlJsLib = require('xml-js');
  11. // @type String The path of the file to read
  12. var filePath;
  13. // @type Array[Track] List of tracks read from the file
  14. const tracks = [];
  15. // @type Date The starting time of the script so that we can calculate the ellapsed time at the end of the script
  16. var startTime;
  17. function main()
  18. {
  19. startTime = new Date();
  20. console.log("Started PhoneTrack GPX file fixer");
  21. if (process.argv.length <= 2)
  22. {
  23. console.log("Please specify file path");
  24. return;
  25. }
  26. filePath = process.argv[2];
  27. console.log("Reading file located at \"" + filePath + "\"...");
  28. // We read the file
  29. fileSystemLib.readFile(filePath, onFileRead);
  30. }
  31. function onFileRead(error, fileData)
  32. {
  33. if (error)
  34. {
  35. throw error;
  36. }
  37. // We read XML dazta from the file (this will throw if the file is not XML)
  38. console.log("File has been read, loading XML...");
  39. let xmlData = xmlJsLib.xml2js(fileData);
  40. console.log("XML has been loaded, reading PhoneTrack data...");
  41. let rootElements = xmlData.elements;
  42. let gpxData = rootElements[0];
  43. let gpxElements = gpxData.elements;
  44. for (let index in gpxElements)
  45. {
  46. let gpxChildData = gpxElements[index];
  47. if (gpxChildData.name === "trk")
  48. {
  49. loadTrack(gpxChildData);
  50. }
  51. }
  52. sortTracks();
  53. updateXml(xmlData);
  54. }
  55. function loadTrack(trackData)
  56. {
  57. let track = new Track(trackData);
  58. tracks.push(track);
  59. }
  60. function sortTracks()
  61. {
  62. console.log("Sorting all points...");
  63. for (let index in tracks)
  64. {
  65. let track = tracks[index];
  66. track.sort();
  67. }
  68. console.log("Done sorting all points");
  69. };
  70. function updateXml(xmlData)
  71. {
  72. console.log("Updating XML...");
  73. for (let index in tracks)
  74. {
  75. let track = tracks[index];
  76. track.sortXml();
  77. }
  78. console.log("Done updating XML");
  79. let newFilePath = filePath + "2";
  80. console.log("Writing to new file \"" + newFilePath + "\"");
  81. let xmlBack = xmlJsLib.js2xml(xmlData, {spaces: 2, indentCdata: true});
  82. fileSystemLib.writeFile(newFilePath, xmlBack, function(error, data)
  83. {
  84. if (error)
  85. {
  86. throw error;
  87. }
  88. console.log("Data written to file");
  89. let endTime = new Date();
  90. let timeDiff = (endTime - startTime) / 1000; //in sec
  91. console.log("Done in " + timeDiff + " sec");
  92. });
  93. };
  94. function Track(trackData)
  95. {
  96. this.m_points = [];
  97. let elementsData = trackData.elements;
  98. for (let index in elementsData)
  99. {
  100. let elementData = elementsData[index];
  101. if (elementData.name === "name")
  102. {
  103. this.m_trackName = elementData.elements[0].text;
  104. }
  105. else if (elementData.name === "trkseg")
  106. {
  107. this.m_pointsData = elementData.elements;
  108. }
  109. }
  110. console.log("Loading track \"" + this.m_trackName + "\" with " + this.m_pointsData.length + " points");
  111. for (let index in this.m_pointsData)
  112. {
  113. let pointData = this.m_pointsData[index];
  114. let point = new Point(pointData);
  115. this.m_points.push(point);
  116. }
  117. console.log("Done loading track \"" + this.m_trackName + "\"");
  118. }
  119. Track.prototype.m_name;
  120. // @type Array[Point]
  121. Track.prototype.m_points;
  122. Track.prototype.sort = function()
  123. {
  124. console.log("Sorting points...");
  125. this.m_points.sort(function(pointA, pointB)
  126. {
  127. return pointA.getTimestamp() - pointB.getTimestamp();
  128. });
  129. console.log("Done reading and sorting track \"" + this.m_trackName + "\"");
  130. };
  131. Track.prototype.sortXml = function()
  132. {
  133. // 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)
  134. this.m_pointsData.splice(0, this.m_pointsData.length);
  135. for (let index in this.m_points)
  136. {
  137. let point = this.m_points[index];
  138. this.m_pointsData.push(point.getData());
  139. }
  140. };
  141. function Point(pointData)
  142. {
  143. this.m_data = pointData;
  144. this.m_timestamp = new Date(this.m_data.elements[0].elements[0].text).getTime();
  145. }
  146. Point.prototype.m_data;
  147. Point.prototype.m_timestamp;
  148. Point.prototype.getData = function()
  149. {
  150. return this.m_data;
  151. };
  152. Point.prototype.getTimestamp = function()
  153. {
  154. return this.m_timestamp;
  155. };
  156. // Execution of the script
  157. main();