garminclimb 1.0.5 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm install:*)",
5
+ "Bash(find /Users/johnottenlips/garminclimb/node_modules/garmin-connect/dist -name \"activity*\" -o -name \"types*\" 2>/dev/null | head -20)",
6
+ "Bash(npx tsc:*)",
7
+ "Bash(node dist/index.js charts 2>&1 | tail -80)",
8
+ "Bash(node bin/index.js charts 2>&1 | grep -A 2 \"Strength Training\")",
9
+ "Bash(node bin/index.js charts 2>&1 | tail -120)",
10
+ "Bash(node bin/index.js chartjs)",
11
+ "Read(//tmp/**)",
12
+ "Bash(open /tmp/strength_test.html)",
13
+ "Bash(cat ~/.gc_data/indoorClimbingActivities.json | python3 -c \"import json,sys; data=json.load\\(sys.stdin\\); print\\(f'Activities: {len\\(data\\)}'\\); [print\\(f' {a[\\\\\"startTimeLocal\\\\\"]} - {a[\\\\\"activityName\\\\\"]}'\\) for a in data[:5]]\" 2>&1)",
14
+ "Bash(cat ~/.gc_data/strengthTrainingActivities.json | python3 -c \"\nimport json,sys\ndata=json.load\\(sys.stdin\\)\nprint\\(f'Activities: {len\\(data\\)}'\\)\nfor a in data[:3]:\n print\\(f' {a.get\\(\\\\\"startTimeLocal\\\\\"\\)} - {a.get\\(\\\\\"activityName\\\\\"\\)}'\\)\n sets = a.get\\('exerciseSets'\\) or a.get\\('summarizedExerciseSets'\\) or []\n print\\(f' exerciseSets: {len\\(sets\\)} sets'\\)\n for s in sets[:3]:\n print\\(f' {s}'\\)\n\" 2>&1)",
15
+ "Bash(chmod +x /Users/johnottenlips/garminclimb/bin/index.js && ls -la /Users/johnottenlips/garminclimb/bin/index.js)",
16
+ "Bash(cat ~/.gc_data/strengthTrainingActivities.json | python3 -c \"\nimport json,sys\ndata=json.load\\(sys.stdin\\)\nprint\\(f'Total activities: {len\\(data\\)}'\\)\nfor a in data[:5]:\n print\\(f' {a.get\\(\\\\\"startTimeLocal\\\\\"\\)} - {a.get\\(\\\\\"activityName\\\\\"\\)}'\\)\n sets = a.get\\('exerciseSets'\\) or a.get\\('fullSummarizedExerciseSets'\\) or a.get\\('summarizedExerciseSets'\\) or []\n print\\(f' sets: {len\\(sets\\)}'\\)\n for s in sets[:4]:\n print\\(f' name={s.get\\(\\\\\"exerciseName\\\\\",\\\\\"?\\\\\"\\)} cat={s.get\\(\\\\\"exerciseCategory\\\\\",\\\\\"?\\\\\"\\)} type={s.get\\(\\\\\"setType\\\\\",\\\\\"?\\\\\"\\)} w={s.get\\(\\\\\"weight\\\\\",\\\\\"?\\\\\"\\)} r={s.get\\(\\\\\"repetitionCount\\\\\",\\\\\"?\\\\\"\\)}'\\)\nprint\\('...'\\)\nfor a in data[-3:]:\n print\\(f' {a.get\\(\\\\\"startTimeLocal\\\\\"\\)} - {a.get\\(\\\\\"activityName\\\\\"\\)}'\\)\n sets = a.get\\('exerciseSets'\\) or a.get\\('fullSummarizedExerciseSets'\\) or a.get\\('summarizedExerciseSets'\\) or []\n print\\(f' sets: {len\\(sets\\)}'\\)\n for s in sets[:4]:\n print\\(f' name={s.get\\(\\\\\"exerciseName\\\\\",\\\\\"?\\\\\"\\)} cat={s.get\\(\\\\\"exerciseCategory\\\\\",\\\\\"?\\\\\"\\)} type={s.get\\(\\\\\"setType\\\\\",\\\\\"?\\\\\"\\)} w={s.get\\(\\\\\"weight\\\\\",\\\\\"?\\\\\"\\)} r={s.get\\(\\\\\"repetitionCount\\\\\",\\\\\"?\\\\\"\\)}'\\)\n\" 2>&1)",
17
+ "Bash(cat ~/.gc_data/strengthTrainingActivities.json | python3 -c \"\nimport json,sys\ndata=json.load\\(sys.stdin\\)\na = data[0]\nsets = a.get\\('exerciseSets'\\) or a.get\\('fullSummarizedExerciseSets'\\) or a.get\\('summarizedExerciseSets'\\) or []\nprint\\('First activity keys:', list\\(a.keys\\(\\)\\)[:20]\\)\nprint\\(\\)\nfor i, s in enumerate\\(sets[:2]\\):\n print\\(f'Set {i} keys: {list\\(s.keys\\(\\)\\)}'\\)\n print\\(json.dumps\\(s, indent=2\\)[:500]\\)\n print\\(\\)\n\" 2>&1)",
18
+ "Bash(node bin/index.js charts 2>&1 | sed -n '/Strength Training/,$p')",
19
+ "Bash(node bin/index.js charts 2>&1 | sed -n '/Weighted Pull-Up/,/```/p' | head -30)",
20
+ "Bash(node bin/index.js charts 2>&1 | grep -A 5 \"Romanian Deadlift\")",
21
+ "Bash(chmod +x /Users/johnottenlips/garminclimb/bin/index.js)",
22
+ "Bash(grep -r \"Cycling\" /Users/johnottenlips/garminclimb/node_modules/garmin-connect/dist/garmin/types/activity* 2>/dev/null | head -20)",
23
+ "Bash(node -e \"const { ActivityType } = require\\('garmin-connect/dist/garmin/types/activity'\\); console.log\\('ActivityType.Cycling =', ActivityType.Cycling\\); console.log\\('All types:', JSON.stringify\\(ActivityType, null, 2\\)\\);\")"
24
+ ]
25
+ }
26
+ }
package/README.md CHANGED
@@ -17,6 +17,48 @@ cd ~/.gc_data
17
17
  ls
18
18
  ```
19
19
 
20
+ # Interactive Chart.js Dashboard
21
+
22
+ Generate a self-contained HTML file with interactive Chart.js graphs. The HTML includes your climbing data inline so it can be opened in any browser without a server.
23
+
24
+ ```shell
25
+ garminclimb chartjs > climbing_dashboard.html
26
+ open climbing_dashboard.html
27
+ ```
28
+
29
+ This outputs a single HTML file with all your data embedded. Charts include:
30
+
31
+ - Yearly and monthly totals for feet climbed (rope, boulder, combined)
32
+ - Yearly and monthly max grades (rope and boulder)
33
+ - Yearly and monthly session counts
34
+ - Per-session stats: max grade, sends, feet, active minutes
35
+ - Per-session bouldering: max grade, splits, active minutes
36
+
37
+ ## Embed in a Markdown File
38
+
39
+ Output an HTML snippet you can paste directly into any markdown file that supports inline HTML (GitHub Pages, Jekyll, static site generators, etc.):
40
+
41
+ ```shell
42
+ garminclimb chartjs-embed > climbing-charts.html
43
+ ```
44
+
45
+ Then include it in your markdown:
46
+
47
+ ```markdown
48
+ # My Climbing Stats
49
+
50
+ Here are my climbing charts from Garmin:
51
+
52
+ {% include climbing-charts.html %}
53
+ ```
54
+
55
+ Or paste the output directly into your `.md` file — the snippet includes scoped CSS (`.gc-dashboard` prefix) so it won't conflict with your site's styles.
56
+
57
+ ```shell
58
+ # Append charts to an existing markdown file
59
+ garminclimb chartjs-embed >> climbing.md
60
+ ```
61
+
20
62
  # Develop locally or make your own charts
21
63
 
22
64
  ```shell
package/bin/download.js CHANGED
@@ -65,6 +65,48 @@ const download = (username, password) => __awaiter(void 0, void 0, void 0, funct
65
65
  const boulderingActivities = activities === null || activities === void 0 ? void 0 : activities.filter((activity) => { var _a; return ((_a = activity === null || activity === void 0 ? void 0 : activity.activityType) === null || _a === void 0 ? void 0 : _a.typeKey) === "bouldering"; });
66
66
  fs.writeFileSync(`${_1.garminDataFolder}/boulderingActivities.json`, JSON.stringify(boulderingActivities, null, 2));
67
67
  console.log("Downloaded climbing activities from Garmin Connect");
68
+ // Download strength training activities
69
+ const strengthActivities = yield GCClient.getActivities(0, 6000, activity_1.ActivityType.FitnessEquipment,
70
+ // @ts-ignore
71
+ "strength_training");
72
+ const strengthTrainingActivities = strengthActivities === null || strengthActivities === void 0 ? void 0 : strengthActivities.filter((activity) => { var _a; return ((_a = activity === null || activity === void 0 ? void 0 : activity.activityType) === null || _a === void 0 ? void 0 : _a.typeKey) === "strength_training"; });
73
+ // Fetch detailed data for each strength activity to get exercise sets
74
+ console.log(`Found ${(strengthTrainingActivities === null || strengthTrainingActivities === void 0 ? void 0 : strengthTrainingActivities.length) || 0} strength training activities, fetching details...`);
75
+ const detailedActivities = [];
76
+ for (const activity of strengthTrainingActivities || []) {
77
+ try {
78
+ const detail = yield GCClient.getActivity({ activityId: activity.activityId });
79
+ detailedActivities.push(Object.assign(Object.assign({}, activity), { exerciseSets: (detail === null || detail === void 0 ? void 0 : detail.exerciseSets) || (detail === null || detail === void 0 ? void 0 : detail.summarizedExerciseSets) || (activity === null || activity === void 0 ? void 0 : activity.summarizedExerciseSets) || [], fullSummarizedExerciseSets: (detail === null || detail === void 0 ? void 0 : detail.summarizedExerciseSets) || (activity === null || activity === void 0 ? void 0 : activity.summarizedExerciseSets) || [] }));
80
+ }
81
+ catch (e) {
82
+ // fallback to list data if detail fetch fails
83
+ detailedActivities.push(activity);
84
+ }
85
+ }
86
+ fs.writeFileSync(`${_1.garminDataFolder}/strengthTrainingActivities.json`, JSON.stringify(detailedActivities, null, 2));
87
+ console.log("Downloaded strength training activities from Garmin Connect");
88
+ // Download running activities (street_running gets all running subtypes)
89
+ const runningActivities = yield GCClient.getActivities(0, 6000,
90
+ // @ts-ignore
91
+ "running");
92
+ const filteredRunning = (runningActivities || []).filter((a) => {
93
+ var _a;
94
+ const key = ((_a = a === null || a === void 0 ? void 0 : a.activityType) === null || _a === void 0 ? void 0 : _a.typeKey) || "";
95
+ return key.includes("running");
96
+ });
97
+ fs.writeFileSync(`${_1.garminDataFolder}/runningActivities.json`, JSON.stringify(filteredRunning, null, 2));
98
+ console.log(`Downloaded ${filteredRunning.length} running activities from Garmin Connect`);
99
+ // Download cycling activities
100
+ const cyclingActivities = yield GCClient.getActivities(0, 6000,
101
+ // @ts-ignore
102
+ "cycling");
103
+ const filteredCycling = (cyclingActivities || []).filter((a) => {
104
+ var _a;
105
+ const key = ((_a = a === null || a === void 0 ? void 0 : a.activityType) === null || _a === void 0 ? void 0 : _a.typeKey) || "";
106
+ return key.includes("cycling") || key.includes("biking") || key === "virtual_ride";
107
+ });
108
+ fs.writeFileSync(`${_1.garminDataFolder}/cyclingActivities.json`, JSON.stringify(filteredCycling, null, 2));
109
+ console.log(`Downloaded ${filteredCycling.length} cycling activities from Garmin Connect`);
68
110
  });
69
111
  exports.download = download;
70
112
  //# sourceMappingURL=download.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,aAAa;AACb,mDAA+C;AAC/C,wBAAqC;AACrC,wEAGmD;AAC5C,MAAM,QAAQ,GAAG,CACtB,QAAgB,EAChB,QAAgB,EACD,EAAE;IACjB,MAAM,QAAQ,GAAG,IAAI,8BAAa,CAAC;QACjC,QAAQ;QACR,QAAQ;KACT,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,aAAa,CAC7C,CAAC,EACD,IAAI,EACJ,uBAAY,CAAC,gBAAgB;IAC7B,aAAa;IACb,iBAAiB,CAClB,CAAC;IAEF,MAAM,wBAAwB,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,MAAM,CACjD,CAAC,QAAQ,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,YAAY,0CAAE,OAAO,MAAK,iBAAiB,CAAA,EAAA,CACpE,CAAC;IAEF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,mBAAgB,CAAC,EAAE,CAAC;QACrC,EAAE,CAAC,SAAS,CAAC,mBAAgB,CAAC,CAAC;IACjC,CAAC;IACD,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,gCAAgC,EACnD,IAAI,CAAC,SAAS,CAAC,wBAAwB,EAAE,IAAI,EAAE,CAAC,CAAC,CAClD,CAAC;IAEF,MAAM,oBAAoB,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,MAAM,CAC7C,CAAC,QAAQ,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,YAAY,0CAAE,OAAO,MAAK,YAAY,CAAA,EAAA,CAC/D,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,4BAA4B,EAC/C,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;AACpE,CAAC,CAAA,CAAC;AAxCW,QAAA,QAAQ,YAwCnB"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../src/download.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,aAAa;AACb,mDAA+C;AAC/C,wBAAqC;AACrC,wEAGmD;AAC5C,MAAM,QAAQ,GAAG,CACtB,QAAgB,EAChB,QAAgB,EACD,EAAE;IACjB,MAAM,QAAQ,GAAG,IAAI,8BAAa,CAAC;QACjC,QAAQ;QACR,QAAQ;KACT,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,aAAa,CAC7C,CAAC,EACD,IAAI,EACJ,uBAAY,CAAC,gBAAgB;IAC7B,aAAa;IACb,iBAAiB,CAClB,CAAC;IAEF,MAAM,wBAAwB,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,MAAM,CACjD,CAAC,QAAQ,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,YAAY,0CAAE,OAAO,MAAK,iBAAiB,CAAA,EAAA,CACpE,CAAC;IAEF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,mBAAgB,CAAC,EAAE,CAAC;QACrC,EAAE,CAAC,SAAS,CAAC,mBAAgB,CAAC,CAAC;IACjC,CAAC;IACD,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,gCAAgC,EACnD,IAAI,CAAC,SAAS,CAAC,wBAAwB,EAAE,IAAI,EAAE,CAAC,CAAC,CAClD,CAAC;IAEF,MAAM,oBAAoB,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,MAAM,CAC7C,CAAC,QAAQ,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,YAAY,0CAAE,OAAO,MAAK,YAAY,CAAA,EAAA,CAC/D,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,4BAA4B,EAC/C,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAElE,wCAAwC;IACxC,MAAM,kBAAkB,GAAG,MAAM,QAAQ,CAAC,aAAa,CACrD,CAAC,EACD,IAAI,EACJ,uBAAY,CAAC,gBAAgB;IAC7B,aAAa;IACb,mBAAmB,CACpB,CAAC;IAEF,MAAM,0BAA0B,GAAG,kBAAkB,aAAlB,kBAAkB,uBAAlB,kBAAkB,CAAE,MAAM,CAC3D,CAAC,QAAa,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,YAAY,0CAAE,OAAO,MAAK,mBAAmB,CAAA,EAAA,CAC3E,CAAC;IAEF,sEAAsE;IACtE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAA,0BAA0B,aAA1B,0BAA0B,uBAA1B,0BAA0B,CAAE,MAAM,KAAI,CAAC,oDAAoD,CAAC,CAAC;IAClH,MAAM,kBAAkB,GAAU,EAAE,CAAC;IACrC,KAAK,MAAM,QAAQ,IAAI,0BAA0B,IAAI,EAAE,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,MAAM,GAAQ,MAAM,QAAQ,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACpF,kBAAkB,CAAC,IAAI,iCAClB,QAAQ,KACX,YAAY,EAAE,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,YAAY,MAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,sBAAsB,CAAA,KAAK,QAAgB,aAAhB,QAAQ,uBAAR,QAAQ,CAAU,sBAAsB,CAAA,IAAI,EAAE,EACvH,0BAA0B,EAAE,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,sBAAsB,MAAK,QAAgB,aAAhB,QAAQ,uBAAR,QAAQ,CAAU,sBAAsB,CAAA,IAAI,EAAE,IAC7G,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,8CAA8C;YAC9C,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,kCAAkC,EACrD,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC,CAC5C,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IAE3E,yEAAyE;IACzE,MAAM,iBAAiB,GAAG,MAAM,QAAQ,CAAC,aAAa,CACpD,CAAC,EACD,IAAI;IACJ,aAAa;IACb,SAAS,CACV,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,MAAM,CACtD,CAAC,CAAM,EAAE,EAAE;;QACT,MAAM,GAAG,GAAG,CAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,YAAY,0CAAE,OAAO,KAAI,EAAE,CAAC;QAC3C,OAAO,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CACF,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,yBAAyB,EAC5C,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CACzC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,cAAc,eAAe,CAAC,MAAM,yCAAyC,CAAC,CAAC;IAE3F,8BAA8B;IAC9B,MAAM,iBAAiB,GAAG,MAAM,QAAQ,CAAC,aAAa,CACpD,CAAC,EACD,IAAI;IACJ,aAAa;IACb,SAAS,CACV,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,MAAM,CACtD,CAAC,CAAM,EAAE,EAAE;;QACT,MAAM,GAAG,GAAG,CAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,YAAY,0CAAE,OAAO,KAAI,EAAE,CAAC;QAC3C,OAAO,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,KAAK,cAAc,CAAC;IACrF,CAAC,CACF,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,GAAG,mBAAgB,yBAAyB,EAC5C,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CACzC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,cAAc,eAAe,CAAC,MAAM,yCAAyC,CAAC,CAAC;AAC7F,CAAC,CAAA,CAAC;AAtHW,QAAA,QAAQ,YAsHnB"}
package/bin/index.js CHANGED
@@ -1,8 +1,42 @@
1
1
  #! /usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
3
36
  Object.defineProperty(exports, "__esModule", { value: true });
4
37
  exports.garminDataFolder = void 0;
5
38
  const commander_1 = require("commander");
39
+ const fs = __importStar(require("fs"));
6
40
  const os = require("os");
7
41
  const path = require("path");
8
42
  const homeDir = os.homedir();
@@ -25,5 +59,75 @@ commander_1.program
25
59
  .action(() => {
26
60
  (0, parse_1.parse)();
27
61
  });
62
+ function loadData() {
63
+ const indoorData = fs.readFileSync(path.join(exports.garminDataFolder, "indoorClimbingActivities.json"), "utf8");
64
+ const boulderData = fs.readFileSync(path.join(exports.garminDataFolder, "boulderingActivities.json"), "utf8");
65
+ let strengthData = "[]";
66
+ try {
67
+ strengthData = fs.readFileSync(path.join(exports.garminDataFolder, "strengthTrainingActivities.json"), "utf8");
68
+ }
69
+ catch (e) { }
70
+ let runningData = "[]";
71
+ try {
72
+ runningData = fs.readFileSync(path.join(exports.garminDataFolder, "runningActivities.json"), "utf8");
73
+ }
74
+ catch (e) { }
75
+ let cyclingData = "[]";
76
+ try {
77
+ cyclingData = fs.readFileSync(path.join(exports.garminDataFolder, "cyclingActivities.json"), "utf8");
78
+ }
79
+ catch (e) { }
80
+ return `var INDOOR_DATA = ${indoorData};\nvar BOULDER_DATA = ${boulderData};\nvar STRENGTH_DATA = ${strengthData};\nvar CYCLING_DATA = ${cyclingData};\nvar RUNNING_DATA = ${runningData};\n`;
81
+ }
82
+ commander_1.program
83
+ .command("chartjs")
84
+ .description("Output a standalone Chart.js HTML dashboard")
85
+ .action(() => {
86
+ const embedHtml = fs.readFileSync(path.join(__dirname, "..", "charts-embed.html"), "utf8");
87
+ const dataScript = loadData();
88
+ const output = `<!DOCTYPE html>
89
+ <html lang="en">
90
+ <head>
91
+ <meta charset="UTF-8">
92
+ <meta name="viewport" content="width=device-width, initial-scale=1">
93
+ <title>Garmin Stats</title>
94
+ <style>
95
+ * { margin: 0; padding: 0; box-sizing: border-box; }
96
+ body {
97
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
98
+ line-height: 1.6;
99
+ color: #333;
100
+ max-width: 720px;
101
+ margin: 0 auto;
102
+ padding: 20px;
103
+ background: #fafaf8;
104
+ }
105
+ h1 { color: #2d5016; margin-bottom: 16px; }
106
+ h2 { color: #3a6b1e; margin: 24px 0 12px; }
107
+ a { color: #2d5016; }
108
+ hr { border: none; border-top: 2px solid #2d5016; margin: 24px 0; }
109
+ @media (max-width: 600px) {
110
+ body { padding: 12px; }
111
+ h1 { font-size: 1.4em; }
112
+ h2 { font-size: 1.15em; }
113
+ }
114
+ </style>
115
+ </head>
116
+ <body>
117
+ <script>${dataScript}</script>
118
+ ${embedHtml}
119
+ </body>
120
+ </html>`;
121
+ console.log(output);
122
+ });
123
+ commander_1.program
124
+ .command("chartjs-embed")
125
+ .description("Output an embeddable Chart.js HTML snippet for markdown files")
126
+ .action(() => {
127
+ const embedHtml = fs.readFileSync(path.join(__dirname, "..", "charts-embed.html"), "utf8");
128
+ const dataScript = loadData();
129
+ const output = embedHtml.replace("<script>\n(function() {", `<script>\n${dataScript}(function() {`);
130
+ console.log(output);
131
+ });
28
132
  commander_1.program.parse();
29
133
  //# sourceMappingURL=index.js.map
package/bin/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAEA,yCAAoC;AACpC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACzB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;AAChB,QAAA,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC/D,yCAAsC;AACtC,mCAAgC;AAEhC,mBAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,2BAA2B,EAAE,yBAAyB,CAAC;KAC9D,MAAM,CAAC,2BAA2B,EAAE,yBAAyB,CAAC;KAC9D,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC;IACzC,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC;IACzC,IAAA,mBAAQ,EAAC,eAAe,EAAE,eAAe,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEL,mBAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,GAAG,EAAE;IACX,IAAA,aAAK,GAAE,CAAC;AACV,CAAC,CAAC,CAAC;AAEL,mBAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ // // https://www.mountainproject.com/rss/user-ticks/201166134
3
+ // // <rss xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
4
+ // // <channel>
5
+ // // <title>Ticks for John Ottenlips Franke on Mountain Project</title>
6
+ // // <description>The Definitive Climbing Resource</description>
7
+ // // <link>https://www.mountainproject.com</link>
8
+ // // <language>en-us</language>
9
+ // // <lastBuildDate>Sat, 24 Jan 2026 19:09:10 +0000</lastBuildDate>
10
+ // // <item>
11
+ // // <title>Tick: Grape Vine (5.7)</title>
12
+ // // <link>https://www.mountainproject.com/route/121871647/grape-vine</link>
13
+ // // <guid isPermaLink="false">MPObject_202273988</guid>
14
+ // // <pubDate>Sat, 27 Dec 2025 21:06:07 +0000</pubDate>
15
+ // // <description><div class="fr-view"><p>Work through a low crux through a series of small ledges. Finish in a small dihedral just before the anchor. Watch out for lots of loose rock.</p></div><br /><img class="" src='https://mountainproject.com/assets/photos/climb/122083536_smallMed_1647451882_topo.jpg?cache=1714597316' alt="Really fun route!"><br><a href="https://www.mountainproject.com/area/105899020/missouri">Missouri</a> &gt; <a href="https://www.mountainproject.com/area/116617972/em-rockwoods-reservation">EM: Rockwoods R&hellip;</a> &gt; <a href="https://www.mountainproject.com/area/121388630/colony-wall">Colony Wall</a> </description>
16
+ // // </item>
17
+ // // <item>
18
+ // // <title>Tick: Xylem (5.10a)</title>
19
+ // // <link>https://www.mountainproject.com/route/121676838/xylem</link>
20
+ // // <guid isPermaLink="false">MPObject_202273688</guid>
21
+ // // <pubDate>Sat, 27 Dec 2025 19:56:10 +0000</pubDate>
22
+ // // <description><div class="fr-view"><p>Begin with a gentle slab start to a comfortable ledge rest, followed by more vertical climbing as the dihedral crack thins into the crux. &nbsp;Careful footwork and body position will help you gain the second ledge to clip the anchors. &nbsp;The dihedral provides some shade, which may be helpful in warmer weather.</p></div><br /><img class="" src='https://mountainproject.com/assets/photos/climb/126305529_smallMed_1717616410.jpg?cache=1725482195' alt="From Above"><br><a href="https://www.mountainproject.com/area/105899020/missouri">Missouri</a> &gt; <a href="https://www.mountainproject.com/area/116617972/em-rockwoods-reservation">EM: Rockwoods R&hellip;</a> &gt; <a href="https://www.mountainproject.com/area/121388630/colony-wall">Colony Wall</a> </description>
23
+ // // </item>
24
+ // // <item>
25
+ // // craswl mtn project urls for route stats
26
+ // import fetch from "node-fetch";
27
+ // import * as xml2js from "xml2js";
28
+ // export const fetchMountainProjectTicks = async (
29
+ // userId: string
30
+ // ): Promise<any[]> => {
31
+ // const url = `https://www.mountainproject.com/rss/user-ticks/${userId}`;
32
+ // const response = await fetch(url);
33
+ // const xmlData = await response.text();
34
+ // const parser = new xml2js.Parser();
35
+ // const result = await parser.parseStringPromise(xmlData);
36
+ // const items = result.rss.channel[0].item;
37
+ // return items.map((item: any) => ({
38
+ // title: item.title[0],
39
+ // link: item.link[0],
40
+ // pubDate: item.pubDate[0],
41
+ // description: item.description[0],
42
+ // }));
43
+ // };
44
+ // // get route height
45
+ // export const fetchRouteHeight = async (routeUrl: string): Promise<string> => {
46
+ // const response = await fetch(routeUrl);
47
+ // const htmlData = await response.text();
48
+ // const heightMatch = htmlData.match(
49
+ // /<li><strong>Height:<\/strong>\s*([\d\sftm]+)/
50
+ // );
51
+ // if (heightMatch && heightMatch[1]) {
52
+ // return heightMatch[1].trim();
53
+ // }
54
+ // return "Unknown";
55
+ // };
56
+ // // Example usage:
57
+ // // (async () => {
58
+ // // const ticks = await fetchMountainProjectTicks("201166134");
59
+ // // for (const tick of ticks) {
60
+ // // const height = await fetchRouteHeight(tick.link);
61
+ // // console.log(`${tick.title} - Height: ${height}`);
62
+ // // }
63
+ // // })();
64
+ //# sourceMappingURL=mtnproject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mtnproject.js","sourceRoot":"","sources":["../src/mtnproject.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,mLAAmL;AACnL,eAAe;AACf,wEAAwE;AACxE,iEAAiE;AACjE,kDAAkD;AAClD,gCAAgC;AAChC,oEAAoE;AACpE,YAAY;AACZ,2CAA2C;AAC3C,6EAA6E;AAC7E,yDAAyD;AACzD,wDAAwD;AACxD,2oBAA2oB;AAC3oB,aAAa;AACb,YAAY;AACZ,wCAAwC;AACxC,wEAAwE;AACxE,yDAAyD;AACzD,wDAAwD;AACxD,4yBAA4yB;AAC5yB,aAAa;AACb,YAAY;AAEZ,6CAA6C;AAC7C,kCAAkC;AAClC,oCAAoC;AAEpC,mDAAmD;AACnD,mBAAmB;AACnB,yBAAyB;AACzB,4EAA4E;AAC5E,uCAAuC;AACvC,2CAA2C;AAE3C,wCAAwC;AACxC,6DAA6D;AAE7D,8CAA8C;AAC9C,uCAAuC;AACvC,4BAA4B;AAC5B,0BAA0B;AAC1B,gCAAgC;AAChC,wCAAwC;AACxC,SAAS;AACT,KAAK;AACL,sBAAsB;AACtB,iFAAiF;AACjF,4CAA4C;AAC5C,4CAA4C;AAC5C,wCAAwC;AACxC,qDAAqD;AACrD,OAAO;AACP,yCAAyC;AACzC,oCAAoC;AACpC,MAAM;AACN,sBAAsB;AACtB,KAAK;AACL,oBAAoB;AACpB,oBAAoB;AACpB,mEAAmE;AACnE,mCAAmC;AACnC,2DAA2D;AAC3D,2DAA2D;AAC3D,SAAS;AACT,WAAW"}