--- /dev/null
+from os import listdir, path
+from sys import argv
+
+import src.Track_pb2 as track_pb
+from src.gpx_builder import write_gpx_from_mtrack_data
+
+from typing import List, Optional
+
+
+MT_EXT = ".mtrack"
+OPTIONS = {
+ "-t": "tag",
+ "--tag": "tag",
+}
+
+
+def convert_file(path_in: str, keywords: List[str]):
+ track = track_pb.Track()
+ path_out = path.splitext(path_in)[0] + ".gpx"
+ with open(path_in, "rb") as file:
+ track.ParseFromString(file.read())
+ write_gpx_from_mtrack_data(track, path_out, *keywords)
+
+
+def main(args: List[str]):
+ option: Optional[str] = None
+ labels = []
+ path_in = None
+ for arg in args:
+ if option == "tag":
+ labels.append(arg)
+ else:
+ path_in = arg
+
+ option = OPTIONS.get(arg)
+
+ if path_in is None:
+ exit(1)
+
+ if path.isdir(path_in):
+ for file in listdir(path_in):
+ if file.endswith(MT_EXT):
+ file_path = path.join(path_in, file)
+ convert_file(file_path, labels)
+ elif path.isfile(path_in) and path_in.endswith(MT_EXT):
+ convert_file(path_in, labels)
+
+
+if __name__ == "__main__":
+ main(argv[1:])
+
--- /dev/null
+from datetime import datetime
+import xml.etree.ElementTree as ET
+
+from .Track_pb2 import Track
+
+
+KEYWORD_DELIMITER = ','
+NS = {
+ "gpx": "http://www.topografix.com/GPX/1/1"
+}
+
+
+def write_gpx_from_mtrack_data(track: Track, path: str, *keywords: str):
+ root = ET.Element('gpx')
+ tree = ET.ElementTree(root)
+
+ root.attrib['creator'] = "mtrack_to_gpx;see also: Trekarta https://trekarta.info"
+ root.attrib['xmlns'] = NS['gpx']
+
+ md = ET.SubElement(root, 'metadata')
+ md_name = ET.SubElement(md, 'name')
+ md_name.text = track.name
+
+ if len(keywords) > 0:
+ kw_el = ET.SubElement(md, 'keywords')
+ kw_el.text = KEYWORD_DELIMITER.join(keywords)
+
+ trk = ET.SubElement(root, 'trk')
+ trk_name = ET.SubElement(trk, 'name')
+ trk_name.text = track.name
+
+ seg = ET.SubElement(trk, 'trkseg')
+ first_time = None
+ for point in track.points:
+ if not point.continuous:
+ seg = ET.SubElement(trk, 'trkseg')
+ pt = ET.SubElement(seg, 'trkpt')
+ pt.attrib['lat'] = f'{point.latitude_e6/1e6:0.6f}'
+ pt.attrib['lon'] = f'{point.longitude_e6/1e6:0.6f}'
+
+ alt = ET.SubElement(pt, 'ele')
+ alt.text = f'{point.altitude:0.3f}'
+
+ hdop = ET.SubElement(pt, 'hdop')
+ hdop.text = f'{point.accuracy/5:0.6f}'
+
+ bearing = ET.SubElement(pt, 'magvar')
+ bearing.text = f'{point.bearing:0.1f}'
+
+ ts = ET.SubElement(pt, 'time')
+ time = datetime.fromtimestamp(point.timestamp/1000)
+ ts.text = time.isoformat()
+
+ if first_time is None:
+ first_time = time
+
+ if first_time is not None:
+ md_time = ET.SubElement(md, 'time')
+ md_time.text = first_time.isoformat()
+
+ tree.write(
+ path,
+ encoding='UTF-8',
+ xml_declaration=True,
+ )
+