Draw a LiveTrack session's planned course alongside the actual track
Garmin's own LiveTrack page already shows both when the activity was
started from a saved course — the session payload carries the course's
geoPoints right alongside the track points (LiveTrackClient found it
nested under the same React Query cache the session/points come from).
Rendered as a second, dashed LineString distinct from the actual
track's own line ("kind": "actual" vs "planned" on each GeoJSON
feature) — muted gray rather than matching Garmin's own purple-for-
planned, since this app's actual track is already purple and reusing
it would make the two indistinguishable.
This commit is contained in:
1 parent
8eada07869
commit
3106f8c103
4 files changed
+66
-21
No files matched your search
@@ -19,7 +19,7 @@ module Maptool
|
||||
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"
|
||||
PUSH_PATTERN = /self\.__next_f\.push\((\[.*?\])\)<\/script>/m
|
||||
|
||||
Result = Struct.new(:points, :session, keyword_init: true)
|
||||
Result = Struct.new(:points, :session, :course, keyword_init: true)
|
||||
|
||||
def self.fetch(session_id, token)
|
||||
new.fetch(session_id, token)
|
||||
@@ -30,6 +30,10 @@ module Maptool
|
||||
# if that part wasn't found even though points were (seen in practice:
|
||||
# session details are consistently present alongside points, but nothing
|
||||
# here depends on that holding forever).
|
||||
# `course`: the planned route (name/geoPoints), or nil — only present
|
||||
# when the activity was actually started from a saved Garmin course
|
||||
# (session["courseIds"] is how the page itself knows to fetch one; a
|
||||
# plain unplanned activity has neither).
|
||||
def fetch(session_id, token)
|
||||
payloads = parse_payloads(fetch_html(session_id, token))
|
||||
|
||||
@@ -37,8 +41,11 @@ module Maptool
|
||||
raise FetchError, "no track points found (session invalid or expired?)" unless points
|
||||
|
||||
session = search(payloads) { |node| node if node["sessionName"] }
|
||||
# First of possibly several — a LiveTrack session only ever follows
|
||||
# the one course it was started from.
|
||||
course = search(payloads) { |node| node["courses"].first if node["courses"].is_a?(Array) && !node["courses"].empty? }
|
||||
|
||||
Result.new(points: clean(points), session: clean(session))
|
||||
Result.new(points: clean(points), session: clean(session), course: clean(course))
|
||||
end
|
||||
|
||||
# Distance/duration/activity type come from the last track point (its
|
||||
|
||||
Reference in new issue
Block a user