garmsync garmsync
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

85 lines
2.9 KiB

import * as fs from "fs/promises";
import { parseString } from "xml2js";
export function generateTrimlogInput(filename, name = "Walk", type = "walk") {
return new Promise(async(resolve, reject) => {
parseString(await fs.readFile(filename, "utf-8"), (err, res) => {
if (err != null) {
reject(err);
}
const data = res.TrainingCenterDatabase.Activities[0].Activity[0];
const map = {};
const date = new Date(res.TrainingCenterDatabase.Activities[0].Activity[0].Id[0]);
const dateStr = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
let totalCalories = 0;
let minAltitude = null;
let maxAltitude = null;
for (const lap of data.Lap) {
totalCalories += parseFloat(lap.Calories[0]) || 0;
for (const tp of lap.Track[0].Trackpoint) {
const point = {
time: tp.Time[0],
longitude: parseFloat(tp.Position?.[0]?.LongitudeDegrees[0]),
latitude: parseFloat(tp.Position?.[0]?.LatitudeDegrees[0]),
altitude: parseFloat(tp.AltitudeMeters?.[0]),
distance: parseFloat(tp.DistanceMeters?.[0]),
pulse: parseFloat(tp.HeartRateBpm?.[0].Value?.[0]),
};
if (minAltitude == null || point.altitude < minAltitude) {
minAltitude = point.altitude;
}
if (maxAltitude == null || point.altitude > maxAltitude) {
maxAltitude = point.altitude;
}
map[tp.Time[0]] = point;
}
}
const list = Object.keys(map).sort().map(k => map[k]);
const firstLon = list.find(e => !!e.longitude)?.longitude;
const firstLat = list.find(e => !!e.latitude)?.latitude;
const firstAlt = list.find(e => !!e.altitude)?.altitude;
const out = {
date: dateStr,
contents: [{rawActivity: {
kind: type === "cycling" ? "Biking" : "Walking",
sets: [],
effortScale: 1,
weight: 0,
measurements: list.map(p => ({
seconds: Math.round((new Date(p.time) - date) / 1000),
meters: p.distance,
pulse: p.pulse,
longitude: p.longitude || firstLon,
latitude: p.latitude || firstLat,
altitude: p.altitude || firstAlt,
}))
}}],
description: name,
tags: [
{ key: "tcx:Time", value: res.TrainingCenterDatabase.Activities[0].Activity[0].Id[0] },
{ key: "tcx:TotalCalories", value: totalCalories.toFixed(1) },
{ key: "tcx:MaximumAltitude", value: maxAltitude.toFixed(1) },
{ key: "tcx:MinimumAltitude", value: minAltitude.toFixed(1) },
]
}
resolve(out);
});
})
}
export function today() {
const date = new Date();
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
}
function pad(n) {return n > 9 ? n.toString() : `0${n}`}