diff options
| -rw-r--r-- | fietsboek/actions.py | 2 | ||||
| -rw-r--r-- | fietsboek/models/track.py | 53 | ||||
| -rw-r--r-- | fietsboek/util.py | 37 | ||||
| -rw-r--r-- | fietsboek/views/browse.py | 2 | ||||
| -rw-r--r-- | fietsboek/views/default.py | 2 | ||||
| -rw-r--r-- | fietsboek/views/detail.py | 2 | ||||
| -rw-r--r-- | fietsboek/views/profile.py | 4 |
7 files changed, 29 insertions, 73 deletions
diff --git a/fietsboek/actions.py b/fietsboek/actions.py index 0e2284b..f49283d 100644 --- a/fietsboek/actions.py +++ b/fietsboek/actions.py @@ -105,7 +105,7 @@ def add_track( # Best time to build the cache is right after the upload, but *after* the # transformers have been applied! - track.ensure_cache(gpx) + track.ensure_cache() dbsession.add(track.cache) LOGGER.debug("Building preview image for %s", track.id) diff --git a/fietsboek/models/track.py b/fietsboek/models/track.py index e9c09d6..7a7aff0 100644 --- a/fietsboek/models/track.py +++ b/fietsboek/models/track.py @@ -445,24 +445,21 @@ class Track(Base): result = ACLHelper().permits(self, principals, "track.view") return isinstance(result, ACLAllowed) - def ensure_cache(self, gpx_data: Union[str, bytes, gpxpy.gpx.GPX]): - """Ensure that a cached version of this track's metadata exists. - - :param gpx_data: GPX data (uncompressed) from which to build the cache. - """ + def ensure_cache(self): + """Ensure that a cached version of this track's metadata exists.""" if self.cache is not None: return self.cache = TrackCache(track=self) - meta = util.tour_metadata(gpx_data) - self.cache.length = meta["length"] - self.cache.uphill = meta["uphill"] - self.cache.downhill = meta["downhill"] - self.cache.moving_time = meta["moving_time"] - self.cache.stopped_time = meta["stopped_time"] - self.cache.max_speed = meta["max_speed"] - self.cache.avg_speed = meta["avg_speed"] - self.cache.start_time = meta["start_time"] - self.cache.end_time = meta["end_time"] + meta = self.path().movement_data() + self.cache.length = meta.length + self.cache.uphill = meta.uphill + self.cache.downhill = meta.downhill + self.cache.moving_time = meta.moving_duration + self.cache.stopped_time = meta.stopped_duration + self.cache.max_speed = meta.maximum_speed + self.cache.avg_speed = meta.average_speed + self.cache.start_time = self.date + self.cache.end_time = self.date + datetime.timedelta(seconds=meta.duration) def text_tags(self): """Returns a set of textual tags. @@ -542,7 +539,7 @@ class Track(Base): class TrackWithMetadata: """A class to add metadata to a :class:`Track`. - This basically caches the result of :func:`fietsboek.util.tour_metadata`, + This basically caches the result of :func:`fietsboek.geo.Path.movement_data`, or uses the track's cache if possible. Loading of the metadata is lazy on first access. The track is accessible as @@ -551,10 +548,9 @@ class TrackWithMetadata: # pylint: disable=too-many-public-methods - def __init__(self, track: Track, data_manager): + def __init__(self, track: Track): self.track = track self.cache = track.cache - self.data_manager = data_manager self._cached_meta: Optional[dict] = None def _meta(self): @@ -562,8 +558,7 @@ class TrackWithMetadata: if self._cached_meta: return self._cached_meta - data = self.data_manager.open(self.track.id).decompress_gpx() - self._cached_meta = util.tour_metadata(data) + self._cached_meta = self.track.path().movement_data() return self._cached_meta @property @@ -573,7 +568,7 @@ class TrackWithMetadata: :return: Length of the track in meters. """ if self.cache is None or self.cache.length is None: - return self._meta()["length"] + return self._meta().length return float(self.cache.length) @property @@ -583,7 +578,7 @@ class TrackWithMetadata: :return: Downhill in meters. """ if self.cache is None or self.cache.downhill is None: - return self._meta()["downhill"] + return self._meta().downhill return float(self.cache.downhill) @property @@ -593,7 +588,7 @@ class TrackWithMetadata: :return: Uphill in meters. """ if self.cache is None or self.cache.uphill is None: - return self._meta()["uphill"] + return self._meta().uphill return float(self.cache.uphill) @property @@ -615,7 +610,7 @@ class TrackWithMetadata: :return: Stopped time in seconds. """ if self.cache is None or self.cache.stopped_time is None: - value = self._meta()["stopped_time"] + value = self._meta().moving_duration else: value = self.cache.stopped_time return datetime.timedelta(seconds=value) @@ -627,7 +622,7 @@ class TrackWithMetadata: :return: Maximum speed in meters/second. """ if self.cache is None or self.cache.max_speed is None: - return self._meta()["max_speed"] + return self._meta().maximum_speed return float(self.cache.max_speed) @property @@ -637,7 +632,7 @@ class TrackWithMetadata: :return: Average speed in meters/second. """ if self.cache is None or self.cache.avg_speed is None: - return self._meta()["avg_speed"] + return self._meta().average_speed return float(self.cache.avg_speed) @property @@ -648,9 +643,7 @@ class TrackWithMetadata: :return: Start time. """ - if self.cache is None or self.cache.start_time is None: - return self._meta()["start_time"] - return self.cache.start_time + return self.track.date @property def end_time(self) -> datetime.datetime: @@ -661,7 +654,7 @@ class TrackWithMetadata: :return: End time. """ if self.cache is None or self.cache.end_time is None: - return self._meta()["end_time"] + return self.track.date + datetime.timedelta(seconds=self._meta().duration) return self.cache.end_time @property diff --git a/fietsboek/util.py b/fietsboek/util.py index 5611c51..27c333d 100644 --- a/fietsboek/util.py +++ b/fietsboek/util.py @@ -173,43 +173,6 @@ def guess_gpx_timezone(gpx: gpxpy.gpx.GPX) -> datetime.tzinfo: return datetime.timezone.utc -def tour_metadata(gpx_data: Union[str, bytes, gpxpy.gpx.GPX]) -> dict: - """Calculate the metadata of the tour. - - Returns a dict with ``length``, ``uphill``, ``downhill``, ``moving_time``, - ``stopped_time``, ``max_speed``, ``avg_speed``, ``start_time`` and - ``end_time``. - - :param gpx_data: The GPX data of the tour. Can be pre-parsed to save time. - :return: A dictionary with the computed values. - """ - if isinstance(gpx_data, bytes): - gpx_data = gpx_data.decode("utf-8") - if isinstance(gpx_data, gpxpy.gpx.GPX): - gpx = gpx_data - else: - gpx = gpxpy.parse(gpx_data) - timezone = guess_gpx_timezone(gpx) - uphill, downhill = gpx.get_uphill_downhill() - moving_data = gpx.get_moving_data() - time_bounds = gpx.get_time_bounds() - try: - avg_speed = moving_data.moving_distance / moving_data.moving_time - except ZeroDivisionError: - avg_speed = 0.0 - return { - "length": gpx.length_3d(), - "uphill": uphill, - "downhill": downhill, - "moving_time": moving_data.moving_time, - "stopped_time": moving_data.stopped_time, - "max_speed": moving_data.max_speed, - "avg_speed": avg_speed, - "start_time": (time_bounds.start_time or DEFAULT_START_TIME).astimezone(timezone), - "end_time": (time_bounds.end_time or DEFAULT_END_TIME).astimezone(timezone), - } - - def mps_to_kph(mps: float) -> float: """Converts meters/second to kilometers/hour. diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py index e8e3edf..a9e9d2e 100644 --- a/fietsboek/views/browse.py +++ b/fietsboek/views/browse.py @@ -463,7 +463,7 @@ def paginate( break for track in tracks: - track = TrackWithMetadata(track, data_manager) + track = TrackWithMetadata(track) if filters.apply(track): num_retrieved += 1 yield track diff --git a/fietsboek/views/default.py b/fietsboek/views/default.py index 8a9718d..320d02d 100644 --- a/fietsboek/views/default.py +++ b/fietsboek/views/default.py @@ -61,7 +61,7 @@ def home(request: Request) -> Response: gpx_data = request.data_manager.open(track.id).decompress_gpx() track.ensure_cache(gpx_data) request.dbsession.add(track.cache) - summary.add(TrackWithMetadata(track, request.data_manager)) + summary.add(TrackWithMetadata(track)) unfinished_uploads = request.identity.uploads diff --git a/fietsboek/views/detail.py b/fietsboek/views/detail.py index 2f2d887..5fa3beb 100644 --- a/fietsboek/views/detail.py +++ b/fietsboek/views/detail.py @@ -107,7 +107,7 @@ def details(request): # Strip off the sort key again images = [(image[1], image[2]) for image in images] - with_meta = TrackWithMetadata(track, request.data_manager) + with_meta = TrackWithMetadata(track) return { "track": with_meta, "show_organic": track.show_organic_data(), diff --git a/fietsboek/views/profile.py b/fietsboek/views/profile.py index 15bc46c..2e18c19 100644 --- a/fietsboek/views/profile.py +++ b/fietsboek/views/profile.py @@ -54,7 +54,7 @@ def profile_data(request: Request) -> dict: query = select(aliased(models.Track, query)).where(query.c.type == TrackType.ORGANIC) track: models.Track for track in request.dbsession.execute(query).scalars(): - meta = TrackWithMetadata(track, request.data_manager) + meta = TrackWithMetadata(track) total.add(meta) total.moving_time = util.round_to_seconds(total.moving_time) @@ -340,7 +340,7 @@ def json_summary(request: Request) -> Response: if track.cache is None: LOGGER.debug("Skipping track %d as it has no cached metadata", track.id) continue - summary.add(TrackWithMetadata(track, request.data_manager)) + summary.add(TrackWithMetadata(track)) return {y.year: {m.month: m.total_length for m in y} for y in summary} |
