aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/__init__.py1
-rw-r--r--fietsboek/jinja2.py11
-rw-r--r--fietsboek/locale/de/LC_MESSAGES/messages.mobin15962 -> 16196 bytes
-rw-r--r--fietsboek/locale/de/LC_MESSAGES/messages.po34
-rw-r--r--fietsboek/locale/en/LC_MESSAGES/messages.mobin14924 -> 15148 bytes
-rw-r--r--fietsboek/locale/en/LC_MESSAGES/messages.po34
-rw-r--r--fietsboek/locale/fietslog.pot38
-rw-r--r--fietsboek/summaries.py142
-rw-r--r--fietsboek/templates/home.jinja219
-rw-r--r--fietsboek/util.py9
-rw-r--r--fietsboek/views/profile.py119
11 files changed, 258 insertions, 149 deletions
diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py
index bc93408..3d6c125 100644
--- a/fietsboek/__init__.py
+++ b/fietsboek/__init__.py
@@ -181,6 +181,7 @@ def main(global_config, **settings):
jinja2_env.filters["format_datetime"] = mod_jinja2.filter_format_datetime
jinja2_env.filters["format_date"] = mod_jinja2.filter_format_date
jinja2_env.filters["local_datetime"] = mod_jinja2.filter_local_datetime
+ jinja2_env.filters["round_to_seconds"] = mod_jinja2.filter_round_to_seconds
jinja2_env.globals["embed_tile_layers"] = mod_jinja2.global_embed_tile_layers
jinja2_env.globals["list_languages"] = mod_jinja2.global_list_languages
jinja2_env.globals["list_transformers"] = transformers.list_transformers
diff --git a/fietsboek/jinja2.py b/fietsboek/jinja2.py
index 7559f26..5872db5 100644
--- a/fietsboek/jinja2.py
+++ b/fietsboek/jinja2.py
@@ -93,6 +93,17 @@ def filter_local_datetime(ctx: Context, value: datetime.datetime) -> Markup:
)
+def filter_round_to_seconds(value: datetime.datetime) -> datetime.datetime:
+ """Rounds a timedelta to second accuracy.
+
+ Uses :func:`.util.round_to_seconds`.
+
+ :param value: The value to round.
+ :return: The rounded value.
+ """
+ return util.round_to_seconds(value)
+
+
def global_embed_tile_layers(request: Request) -> Markup:
"""Renders the available tile servers for the current user, as a JSON object.
diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.mo b/fietsboek/locale/de/LC_MESSAGES/messages.mo
index 204c8c5..9de152c 100644
--- a/fietsboek/locale/de/LC_MESSAGES/messages.mo
+++ b/fietsboek/locale/de/LC_MESSAGES/messages.mo
Binary files differ
diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.po b/fietsboek/locale/de/LC_MESSAGES/messages.po
index 7c497de..ccb46a3 100644
--- a/fietsboek/locale/de/LC_MESSAGES/messages.po
+++ b/fietsboek/locale/de/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2024-11-16 23:44+0100\n"
+"POT-Creation-Date: 2025-01-30 21:50+0100\n"
"PO-Revision-Date: 2022-07-02 17:35+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
@@ -29,11 +29,11 @@ msgstr ""
"\n"
"Falls Du kein Konto angelegt hast, ignoriere diese E-Mail."
-#: fietsboek/util.py:324
+#: fietsboek/util.py:333
msgid "password_constraint.mismatch"
msgstr "Passwörter stimmen nicht überein"
-#: fietsboek/util.py:326
+#: fietsboek/util.py:335
msgid "password_constraint.length"
msgstr "Passwort zu kurz"
@@ -53,11 +53,11 @@ msgstr "Bergauf"
msgid "tooltip.table.downhill"
msgstr "Bergab"
-#: fietsboek/models/track.py:607
+#: fietsboek/models/track.py:607 fietsboek/templates/home.jinja2:7
msgid "tooltip.table.moving_time"
msgstr "Fahrzeit"
-#: fietsboek/models/track.py:608
+#: fietsboek/models/track.py:608 fietsboek/templates/home.jinja2:8
msgid "tooltip.table.stopped_time"
msgstr "Haltezeit"
@@ -517,24 +517,40 @@ msgstr "Absenden"
msgid "page.upload.form.cancel"
msgstr "Abbrechen"
+#: fietsboek/templates/home.jinja2:5
+msgid "tooltip.table.max_length"
+msgstr "Maximallänge"
+
#: fietsboek/templates/home.jinja2:6
+msgid "tooltip.table.avg_length"
+msgstr "Durchschnittslänge"
+
+#: fietsboek/templates/home.jinja2:9
+msgid "tooltip.table.max_duration"
+msgstr "Maximaldauer"
+
+#: fietsboek/templates/home.jinja2:10
+msgid "tooltip.table.avg_duration"
+msgstr "Durchschnittsdauer"
+
+#: fietsboek/templates/home.jinja2:17
msgid "page.home.title"
msgstr "Startseite"
-#: fietsboek/templates/home.jinja2:17
+#: fietsboek/templates/home.jinja2:28
msgid "page.home.unfinished_uploads"
msgstr ""
"Es sind noch nicht abgeschlossene Uploads vorhanden. Klicke auf die "
"Links, um sie fortzusetzen:"
-#: fietsboek/templates/home.jinja2:31 fietsboek/templates/home.jinja2:38
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:44 fietsboek/templates/home.jinja2:53
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.summary.track"
msgid_plural "page.home.summary.tracks"
msgstr[0] "%(num)d Strecke"
msgstr[1] "%(num)d Strecken"
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.total"
msgstr "Gesamt"
diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.mo b/fietsboek/locale/en/LC_MESSAGES/messages.mo
index e688c2e..5f8edc6 100644
--- a/fietsboek/locale/en/LC_MESSAGES/messages.mo
+++ b/fietsboek/locale/en/LC_MESSAGES/messages.mo
Binary files differ
diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.po b/fietsboek/locale/en/LC_MESSAGES/messages.po
index d9f61d6..981d134 100644
--- a/fietsboek/locale/en/LC_MESSAGES/messages.po
+++ b/fietsboek/locale/en/LC_MESSAGES/messages.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2024-11-16 23:44+0100\n"
+"POT-Creation-Date: 2025-01-30 21:50+0100\n"
"PO-Revision-Date: 2023-04-03 20:42+0200\n"
"Last-Translator: \n"
"Language: en\n"
@@ -29,11 +29,11 @@ msgstr ""
"\n"
"If you did not create an account, ignore this email."
-#: fietsboek/util.py:324
+#: fietsboek/util.py:333
msgid "password_constraint.mismatch"
msgstr "Passwords don't match"
-#: fietsboek/util.py:326
+#: fietsboek/util.py:335
msgid "password_constraint.length"
msgstr "Password not long enough"
@@ -53,11 +53,11 @@ msgstr "Uphill"
msgid "tooltip.table.downhill"
msgstr "Downhill"
-#: fietsboek/models/track.py:607
+#: fietsboek/models/track.py:607 fietsboek/templates/home.jinja2:7
msgid "tooltip.table.moving_time"
msgstr "Moving Time"
-#: fietsboek/models/track.py:608
+#: fietsboek/models/track.py:608 fietsboek/templates/home.jinja2:8
msgid "tooltip.table.stopped_time"
msgstr "Stopped Time"
@@ -513,22 +513,38 @@ msgstr "Upload"
msgid "page.upload.form.cancel"
msgstr "Cancel"
+#: fietsboek/templates/home.jinja2:5
+msgid "tooltip.table.max_length"
+msgstr "Max Length"
+
#: fietsboek/templates/home.jinja2:6
+msgid "tooltip.table.avg_length"
+msgstr "Average Length"
+
+#: fietsboek/templates/home.jinja2:9
+msgid "tooltip.table.max_duration"
+msgstr "Max Duration"
+
+#: fietsboek/templates/home.jinja2:10
+msgid "tooltip.table.avg_duration"
+msgstr "Average Duration"
+
+#: fietsboek/templates/home.jinja2:17
msgid "page.home.title"
msgstr "Home"
-#: fietsboek/templates/home.jinja2:17
+#: fietsboek/templates/home.jinja2:28
msgid "page.home.unfinished_uploads"
msgstr "You have unfinished uploads. Click on the links below to resume them:"
-#: fietsboek/templates/home.jinja2:31 fietsboek/templates/home.jinja2:38
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:44 fietsboek/templates/home.jinja2:53
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.summary.track"
msgid_plural "page.home.summary.tracks"
msgstr[0] "%(num)d track"
msgstr[1] "%(num)d tracks"
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.total"
msgstr "Total"
diff --git a/fietsboek/locale/fietslog.pot b/fietsboek/locale/fietslog.pot
index b14f14e..60c77a5 100644
--- a/fietsboek/locale/fietslog.pot
+++ b/fietsboek/locale/fietslog.pot
@@ -1,14 +1,14 @@
# Translations template for PROJECT.
-# Copyright (C) 2024 ORGANIZATION
+# Copyright (C) 2025 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2024-11-16 23:44+0100\n"
+"POT-Creation-Date: 2025-01-30 21:50+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -25,11 +25,11 @@ msgstr ""
msgid "email.verify.text"
msgstr ""
-#: fietsboek/util.py:324
+#: fietsboek/util.py:333
msgid "password_constraint.mismatch"
msgstr ""
-#: fietsboek/util.py:326
+#: fietsboek/util.py:335
msgid "password_constraint.length"
msgstr ""
@@ -49,11 +49,11 @@ msgstr ""
msgid "tooltip.table.downhill"
msgstr ""
-#: fietsboek/models/track.py:607
+#: fietsboek/models/track.py:607 fietsboek/templates/home.jinja2:7
msgid "tooltip.table.moving_time"
msgstr ""
-#: fietsboek/models/track.py:608
+#: fietsboek/models/track.py:608 fietsboek/templates/home.jinja2:8
msgid "tooltip.table.stopped_time"
msgstr ""
@@ -507,22 +507,38 @@ msgstr ""
msgid "page.upload.form.cancel"
msgstr ""
+#: fietsboek/templates/home.jinja2:5
+msgid "tooltip.table.max_length"
+msgstr ""
+
#: fietsboek/templates/home.jinja2:6
-msgid "page.home.title"
+msgid "tooltip.table.avg_length"
+msgstr ""
+
+#: fietsboek/templates/home.jinja2:9
+msgid "tooltip.table.max_duration"
+msgstr ""
+
+#: fietsboek/templates/home.jinja2:10
+msgid "tooltip.table.avg_duration"
msgstr ""
#: fietsboek/templates/home.jinja2:17
+msgid "page.home.title"
+msgstr ""
+
+#: fietsboek/templates/home.jinja2:28
msgid "page.home.unfinished_uploads"
msgstr ""
-#: fietsboek/templates/home.jinja2:31 fietsboek/templates/home.jinja2:38
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:44 fietsboek/templates/home.jinja2:53
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.summary.track"
msgid_plural "page.home.summary.tracks"
msgstr[0] ""
msgstr[1] ""
-#: fietsboek/templates/home.jinja2:82
+#: fietsboek/templates/home.jinja2:97
msgid "page.home.total"
msgstr ""
diff --git a/fietsboek/summaries.py b/fietsboek/summaries.py
index 9721de2..a0bd7d0 100644
--- a/fietsboek/summaries.py
+++ b/fietsboek/summaries.py
@@ -1,8 +1,11 @@
"""Module for a yearly/monthly track summary."""
-from typing import Dict, List
+import datetime
+from dataclasses import dataclass
+from typing import Dict, List, Optional
-from fietsboek.models.track import TrackWithMetadata
+from . import util
+from .models.track import TrackWithMetadata
class Summary:
@@ -56,6 +59,13 @@ class Summary:
"""
return sum(track.length for track in self.all_tracks())
+ def stats(self) -> "CumulativeStats":
+ """Returns the stats for all tracks in this summary.
+
+ :return: The stats.
+ """
+ return CumulativeStats.from_tracks(self.all_tracks())
+
class YearSummary:
"""A summary over a single year.
@@ -108,6 +118,13 @@ class YearSummary:
"""
return sum(track.length for track in self.all_tracks())
+ def stats(self) -> "CumulativeStats":
+ """Returns the stats for all tracks in this summary.
+
+ :return: The stats.
+ """
+ return CumulativeStats.from_tracks(self.all_tracks())
+
class MonthSummary:
"""A summary over a single month.
@@ -154,3 +171,124 @@ class MonthSummary:
:return: The total length in meters.
"""
return sum(track.length for track in self.all_tracks())
+
+ def stats(self) -> "CumulativeStats":
+ """Returns the stats for all tracks in this summary.
+
+ :return: The stats.
+ """
+ return CumulativeStats.from_tracks(self.all_tracks())
+
+
+@dataclass
+class CumulativeStats:
+ """Cumulative user stats.
+
+ The values start out with default values, and tracks can be merged in via
+ :meth:`add`.
+ """
+
+ # pylint: disable=too-many-instance-attributes
+
+ count: int = 0
+ """Number of tracks added."""
+
+ length: float = 0.0
+ """Total length, in meters."""
+
+ uphill: float = 0.0
+ """Total uphill, in meters."""
+
+ downhill: float = 0.0
+ """Total downhill, in meters."""
+
+ moving_time: datetime.timedelta = datetime.timedelta(0)
+ """Total time spent moving."""
+
+ stopped_time: datetime.timedelta = datetime.timedelta(0)
+ """Total time standing still."""
+
+ max_speed: float = 0.0
+ """Overall maximum speed, in m/s."""
+
+ longest_distance_track: Optional[TrackWithMetadata] = None
+ """The track with the longest distance."""
+
+ shortest_distance_track: Optional[TrackWithMetadata] = None
+ """The track with the shortest distance."""
+
+ longest_duration_track: Optional[TrackWithMetadata] = None
+ """The track with the longest time."""
+
+ shortest_duration_track: Optional[TrackWithMetadata] = None
+ """The track with the shortest time."""
+
+ @classmethod
+ def from_tracks(cls, tracks: List[TrackWithMetadata]) -> "CumulativeStats":
+ """Create a new stats collection from this list of tracks.
+
+ :param tracks: List of tracks.
+ :return: The stats.
+ """
+ stats = cls()
+ for track in tracks:
+ stats.add(track)
+ return stats
+
+ def add(self, track: TrackWithMetadata):
+ """Adds a track to this stats collection.
+
+ :param track: The track to add, with accompanying metadata.
+ """
+ self.count += 1
+ self.length += track.length
+ self.uphill += track.uphill
+ self.downhill += track.downhill
+ self.moving_time += track.moving_time
+ self.stopped_time += track.stopped_time
+ self.max_speed = max(self.max_speed, track.max_speed)
+
+ if self.longest_distance_track is None or self.longest_distance_track.length < track.length:
+ self.longest_distance_track = track
+
+ if (
+ self.shortest_distance_track is None
+ or self.shortest_distance_track.length > track.length
+ ):
+ self.shortest_distance_track = track
+
+ if (
+ self.longest_duration_track is None
+ or self.longest_duration_track.duration < track.duration
+ ):
+ self.longest_duration_track = track
+
+ if (
+ self.shortest_duration_track is None
+ or self.shortest_duration_track.duration > track.duration
+ ):
+ self.shortest_duration_track = track
+
+ @property
+ def avg_speed(self) -> float:
+ """Average speed, in m/s."""
+ if not self.moving_time:
+ return 0.0
+ return self.length / self.moving_time.total_seconds()
+
+ @property
+ def avg_length(self) -> float:
+ """Average length, in m."""
+ if not self.count:
+ return 0
+ return self.length / self.count
+
+ @property
+ def avg_duration(self) -> datetime.timedelta:
+ """Average duration of a track.
+
+ Note that this property is automatically rounded to seconds.
+ """
+ if not self.count:
+ return datetime.timedelta()
+ return util.round_to_seconds((self.moving_time + self.stopped_time) / self.count)
diff --git a/fietsboek/templates/home.jinja2 b/fietsboek/templates/home.jinja2
index e9e1d42..c723b3c 100644
--- a/fietsboek/templates/home.jinja2
+++ b/fietsboek/templates/home.jinja2
@@ -1,5 +1,16 @@
{% extends "layout.jinja2" %}
+{% macro render_html_tooltip(stats) -%}
+<table>
+ <tr><td>{{ _("tooltip.table.max_length") }}</td><td>{{ (stats.longest_distance_track.length / 1000) | round(2) | format_decimal }} km</td></tr>
+ <tr><td>{{ _("tooltip.table.avg_length") }}</td><td>{{ (stats.avg_length / 1000) | round(2) | format_decimal }} km</td></tr>
+ <tr><td>{{ _("tooltip.table.moving_time") }}</td><td>{{ stats.moving_time | round_to_seconds }}</td></tr>
+ <tr><td>{{ _("tooltip.table.stopped_time") }}</td><td>{{ stats.stopped_time | round_to_seconds }}</td></tr>
+ <tr><td>{{ _("tooltip.table.max_duration") }}</td><td>{{ stats.longest_duration_track.duration | round_to_seconds }}</td></tr>
+ <tr><td>{{ _("tooltip.table.avg_duration") }}</td><td>{{ stats.avg_duration | round_to_seconds }}</td></tr>
+</table>
+{%- endmacro %}
+
{% block content %}
<div class="container">
<div class="clearfix">
@@ -27,14 +38,18 @@
{% for year in summary %}
<a class="list-group-item list-group-item-primary">
<i class="bi bi-chevron-down summary-toggler"></i>
- {{ year.year }}
+ <span data-bs-toggle="tooltip" data-bs-container="body" data-bs-html="true" title="{{ render_html_tooltip(year.stats()) }}">
+ {{ year.year }}
+ </span>
<span class="float-end">{{ ngettext("page.home.summary.track", "page.home.summary.tracks", year|length) }} &mdash; {{ (year.total_length / 1000) | round(2) | format_decimal }} km</span>
</a>
<div class="list-group collapse show">
{% for month in year %}
<a class="list-group-item list-group-item-secondary">
<i class="bi bi-chevron-down summary-toggler"></i>
- {{ month_name(request, month.month) }}
+ <span data-bs-toggle="tooltip" data-bs-container="body" data-bs-html="true" title="{{ render_html_tooltip(month.stats()) }}">
+ {{ month_name(request, month.month) }}
+ </span>
<span class="float-end">{{ ngettext("page.home.summary.track", "page.home.summary.tracks", month|length) }} &mdash; {{ (month.total_length / 1000) | round(2) | format_decimal }} km</span>
</a>
<div class="list-group collapse show">
diff --git a/fietsboek/util.py b/fietsboek/util.py
index 1d29600..47e7b7f 100644
--- a/fietsboek/util.py
+++ b/fietsboek/util.py
@@ -110,6 +110,15 @@ def round_timedelta_to_multiple(
return datetime.timedelta(seconds=lower) + multiples
+def round_to_seconds(value: datetime.timedelta) -> datetime.timedelta:
+ """Round a timedelta to full seconds.
+
+ :param value: The input value.
+ :return: The rounded value.
+ """
+ return round_timedelta_to_multiple(value, datetime.timedelta(seconds=1))
+
+
def guess_gpx_timezone(gpx: gpxpy.gpx.GPX) -> datetime.tzinfo:
"""Guess which timezone the GPX file was recorded in.
diff --git a/fietsboek/views/profile.py b/fietsboek/views/profile.py
index 38bdcdc..1208e93 100644
--- a/fietsboek/views/profile.py
+++ b/fietsboek/views/profile.py
@@ -4,8 +4,6 @@ import datetime
import logging
import sqlite3
import urllib.parse
-from dataclasses import dataclass
-from typing import Optional
import sqlalchemy
from pyramid.httpexceptions import HTTPNotFound
@@ -18,7 +16,7 @@ from sqlalchemy.orm import aliased
from .. import models, util
from ..data import DataManager, UserDataDir
from ..models.track import TrackType, TrackWithMetadata
-from ..summaries import Summary
+from ..summaries import CumulativeStats, Summary
# A well-made transparent tile is actually pretty small (only 116 bytes), which
# is even smaller than our HTTP 404 page. So not only is it more efficient
@@ -48,117 +46,6 @@ EMPTY_TILE = bytes([
LOGGER = logging.getLogger(__name__)
-@dataclass
-class CumulativeStats:
- """Cumulative user stats.
-
- The values start out with default values, and tracks can be merged in via
- :meth:`add`.
- """
-
- # pylint: disable=too-many-instance-attributes
-
- count: int = 0
- """Number of tracks added."""
-
- length: float = 0.0
- """Total length, in meters."""
-
- uphill: float = 0.0
- """Total uphill, in meters."""
-
- downhill: float = 0.0
- """Total downhill, in meters."""
-
- moving_time: datetime.timedelta = datetime.timedelta(0)
- """Total time spent moving."""
-
- stopped_time: datetime.timedelta = datetime.timedelta(0)
- """Total time standing still."""
-
- max_speed: float = 0.0
- """Overall maximum speed, in m/s."""
-
- longest_distance_track: Optional[TrackWithMetadata] = None
- """The track with the longest distance."""
-
- shortest_distance_track: Optional[TrackWithMetadata] = None
- """The track with the shortest distance."""
-
- longest_duration_track: Optional[TrackWithMetadata] = None
- """The track with the longest time."""
-
- shortest_duration_track: Optional[TrackWithMetadata] = None
- """The track with the shortest time."""
-
- def add(self, track: TrackWithMetadata):
- """Adds a track to this stats collection.
-
- :param track: The track to add, with accompanying metadata.
- """
- self.count += 1
- self.length += track.length
- self.uphill += track.uphill
- self.downhill += track.downhill
- self.moving_time += track.moving_time
- self.stopped_time += track.stopped_time
- self.max_speed = max(self.max_speed, track.max_speed)
-
- if self.longest_distance_track is None or self.longest_distance_track.length < track.length:
- self.longest_distance_track = track
-
- if (
- self.shortest_distance_track is None
- or self.shortest_distance_track.length > track.length
- ):
- self.shortest_distance_track = track
-
- if (
- self.longest_duration_track is None
- or self.longest_duration_track.duration < track.duration
- ):
- self.longest_duration_track = track
-
- if (
- self.shortest_duration_track is None
- or self.shortest_duration_track.duration > track.duration
- ):
- self.shortest_duration_track = track
-
- @property
- def avg_speed(self) -> float:
- """Average speed, in m/s."""
- if not self.moving_time:
- return 0.0
- return self.length / self.moving_time.total_seconds()
-
- @property
- def avg_length(self) -> float:
- """Average length, in m."""
- if not self.count:
- return 0
- return self.length / self.count
-
- @property
- def avg_duration(self) -> datetime.timedelta:
- """Average duration of a track.
-
- Note that this property is automatically rounded to seconds.
- """
- if not self.count:
- return datetime.timedelta()
- return round_to_seconds((self.moving_time + self.stopped_time) / self.count)
-
-
-def round_to_seconds(value: datetime.timedelta) -> datetime.timedelta:
- """Round a timedelta to full seconds.
-
- :param value: The input value.
- :return: The rounded value.
- """
- return util.round_timedelta_to_multiple(value, datetime.timedelta(seconds=1))
-
-
def profile_data(request: Request) -> dict:
"""Retrieves the profile data for the given request."""
total = CumulativeStats()
@@ -170,8 +57,8 @@ def profile_data(request: Request) -> dict:
meta = TrackWithMetadata(track, request.data_manager)
total.add(meta)
- total.moving_time = round_to_seconds(total.moving_time)
- total.stopped_time = round_to_seconds(total.stopped_time)
+ total.moving_time = util.round_to_seconds(total.moving_time)
+ total.stopped_time = util.round_to_seconds(total.stopped_time)
user_id = request.context.id
heatmap_url = None