Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save VeryCrazyDog/c4b1006d7d86a29395861ccac185cfec to your computer and use it in GitHub Desktop.
Save VeryCrazyDog/c4b1006d7d86a29395861ccac185cfec to your computer and use it in GitHub Desktop.
Download all workouts from sports-tracker
// VCD: Change folder and file name, add metadata file, script shall be executed in Google Chrome.
// 'Show more' button shall be pressed until all workout are shown on page. You might have
// to manually filter out some control characters in the generated script. Works on 2020-11-21.
//
// Bilan: My fork fixed some api changes, added images downloading and informative gpx file names. Works on 2020/11/02.
//
// You can then upload it to Strava using this oneliner:
// find * -name '*.gpx' -print0 | while read -d $'\0' i; do ID=`echo $i | sed 's/.*id--//' | sed 's/--activity.*//'`; ACTIVITY=`echo $i | sed 's/.*--activity--//' | sed 's/--title.*//'`; NAME=`echo $i | sed 's/--file.gpx//' | sed 's/.*--title--//'`" ($ID/$ACTIVITY)"; echo "\n$NAME\n"; curl -X POST https://www.strava.com/api/v3/uploads -H "Authorization: Bearer ___TOKEN___" -F file=@"$i" -F data_type="gpx" -F description="SportsTracker import" -F name="$NAME" -F external_id="$i"; sleep 10;done
//
// Original description:
// based entirely on this blog post:
// http://druss.co/2016/04/export-all-workouts-from-sports-tracker/
// unfortunately the original script no longer works, moslty because jQuery is
// no longer available on sports-tracker pages.
//
// I've compiled the changes proposed in the comments in the script below.
// to use the script, login to your sports-tracker account
// change URL to http://www.sports-tracker.com/diary/workout-list
// open browser console (Cmd-Shift-I)
// paste the script, hit enter - it'll run and print something like this to the cosole:
// curl -o SportsTracker-<..id..>.gpx "http://www.sports-tracker.com/apiserver....."
// right-click on the console and save the contents to a file, call it download-all-workouts.sh
// open terminal, change to the directory where you saved the contents of the console
// edit the file - remove the javascript at the beginning of the file leaving only curl commands
// fix permissions:
// $>chmod +x download-all-workouts.sh
// run the script:
// $>./download-all-workouts.sh
const key = "sessionkey=";
const valueStartIndex = document.cookie.indexOf(key) + key.length;
const token = document.cookie.substring(valueStartIndex, document.cookie.indexOf(';', valueStartIndex));
const activities = {
0: "Walking",
1: "Run",
2: "Cycling",
11: "Hiking",
13: "alpineski",
14: "rowing",
15: "rowing",
26: "Motorsports",
};
function formatDate(value) {
return `${value.getFullYear()}${(value.getMonth() + 1).toString().padStart(2, '0')}${value.getDate().toString().padStart(2, '0')}`
}
async function downloadOne(item) {
const href = item.href;
const id = href.substr(href.lastIndexOf('/') + 1, 24);
const url = 'https://api.sports-tracker.com/apiserver/v1/workout/exportGpx/' + id + '?token=' + token;
const activityTypeId = item.querySelector(".activity-icon").getAttribute('activity-icon');
const activityType = activities[activityTypeId] ?? 'Unknown';
const description = item.querySelector(".description").textContent.trim();
const activityDateText = item.querySelector(".date").textContent.trim();
const activityDate = new Date(activityDateText);
const duration = item.querySelector(".duration").textContent.trim();
const distance = item.querySelector(".distance").textContent.trim();
const avgSpeed = item.querySelector(".avg-speed").textContent.trim();
const avgPace = item.querySelector(".avg-pace").textContent.trim();
const heartRate = item.querySelector(".hr").textContent.trim();
const energy = item.querySelector(".energy").textContent.trim();
const cadence = item.querySelector(".cadence").textContent.trim();
const folderName = `${formatDate(activityDate)}-${activityType}-${id}`;
const filename = `${folderName}.gpx`;
console.log(`mkdir '${folderName}'`);
console.log(`curl -o '${folderName}/${filename}' '${url}';`);
console.log(`echo 'Activity Type: ${activityType}' > '${folderName}/Metadata.txt';`);
console.log(`echo 'Description: ${description}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Activity Date: ${activityDateText}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Duration: ${duration}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Distance: ${distance}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Average Speed: ${avgSpeed}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Average Pace: ${avgPace}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Heart Rate: ${heartRate}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Energy: ${energy}' >> '${folderName}/Metadata.txt';`);
console.log(`echo 'Cadence: ${cadence}' >> '${folderName}/Metadata.txt';`);
await downloadImages(id, folderName);
}
async function downloadImages(id, folderName) {
const imagesUrl = 'https://api.sports-tracker.com/apiserver/v1/images/workout/' + id + '?token=' + token;
const imagesApiResponse = await fetch(imagesUrl);
const images = (await imagesApiResponse.json()).payload;
for (let i = 0; i < images.length; i++) {
let image = images[i];
const imageDate = new Date(image.timestamp);
const filename = `${formatDate(imageDate)}-${image.location.x}-${image.location.y}-${image.key}.jpg`;
let url = `https://api.sports-tracker.com/apiserver/v1/image/scale/${image.key}.jpg?width=${image.width}&height=${image.height}`;
console.log(`curl -o "${folderName}/${filename}" "${url}";`);
}
}
async function loopThroughItems(items) {
for (let i = 0; i < items.length; i++) {
await downloadOne(items[i]);
}
}
const items = document.querySelectorAll("ul.diary-list__workouts li a");
setTimeout(() => {
console.log('Discovered workouts:', items.length)
console.log('-------------- Script Start --------------')
loopThroughItems(items).then(() => {
console.log('-------------- Script End --------------')
console.log(`Finished processing ${items.length} workouts`)
});
}, 1000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment