geo-activity-playground 0.26.3__py3-none-any.whl → 0.27.1__py3-none-any.whl

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.
Files changed (48) hide show
  1. geo_activity_playground/__main__.py +23 -20
  2. geo_activity_playground/core/activities.py +1 -44
  3. geo_activity_playground/core/config.py +111 -0
  4. geo_activity_playground/core/enrichment.py +11 -2
  5. geo_activity_playground/core/heart_rate.py +49 -0
  6. geo_activity_playground/core/paths.py +6 -0
  7. geo_activity_playground/core/tasks.py +14 -0
  8. geo_activity_playground/core/tiles.py +1 -1
  9. geo_activity_playground/explorer/tile_visits.py +23 -11
  10. geo_activity_playground/importers/csv_parser.py +73 -0
  11. geo_activity_playground/importers/directory.py +17 -8
  12. geo_activity_playground/importers/strava_api.py +20 -44
  13. geo_activity_playground/importers/strava_checkout.py +57 -32
  14. geo_activity_playground/importers/test_csv_parser.py +49 -0
  15. geo_activity_playground/webui/activity/blueprint.py +3 -4
  16. geo_activity_playground/webui/activity/controller.py +40 -14
  17. geo_activity_playground/webui/activity/templates/activity/show.html.j2 +6 -2
  18. geo_activity_playground/webui/app.py +26 -26
  19. geo_activity_playground/webui/eddington/controller.py +1 -1
  20. geo_activity_playground/webui/equipment/blueprint.py +5 -2
  21. geo_activity_playground/webui/equipment/controller.py +5 -6
  22. geo_activity_playground/webui/explorer/blueprint.py +14 -2
  23. geo_activity_playground/webui/explorer/controller.py +21 -1
  24. geo_activity_playground/webui/explorer/templates/explorer/index.html.j2 +12 -1
  25. geo_activity_playground/webui/settings/blueprint.py +106 -0
  26. geo_activity_playground/webui/settings/controller.py +228 -0
  27. geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2 +44 -0
  28. geo_activity_playground/webui/settings/templates/settings/heart-rate.html.j2 +102 -0
  29. geo_activity_playground/webui/settings/templates/settings/index.html.j2 +74 -0
  30. geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2 +30 -0
  31. geo_activity_playground/webui/settings/templates/settings/metadata-extraction.html.j2 +55 -0
  32. geo_activity_playground/webui/settings/templates/settings/privacy-zones.html.j2 +81 -0
  33. geo_activity_playground/webui/{strava/templates/strava/client-id.html.j2 → settings/templates/settings/strava.html.j2} +17 -7
  34. geo_activity_playground/webui/templates/home.html.j2 +1 -1
  35. geo_activity_playground/webui/templates/page.html.j2 +5 -1
  36. geo_activity_playground/webui/upload/blueprint.py +10 -1
  37. geo_activity_playground/webui/upload/controller.py +24 -11
  38. geo_activity_playground/webui/upload/templates/upload/reload.html.j2 +16 -0
  39. {geo_activity_playground-0.26.3.dist-info → geo_activity_playground-0.27.1.dist-info}/METADATA +1 -1
  40. {geo_activity_playground-0.26.3.dist-info → geo_activity_playground-0.27.1.dist-info}/RECORD +43 -36
  41. geo_activity_playground/webui/strava/__init__.py +0 -0
  42. geo_activity_playground/webui/strava/blueprint.py +0 -33
  43. geo_activity_playground/webui/strava/controller.py +0 -49
  44. geo_activity_playground/webui/strava/templates/strava/connected.html.j2 +0 -14
  45. geo_activity_playground/webui/templates/settings.html.j2 +0 -24
  46. {geo_activity_playground-0.26.3.dist-info → geo_activity_playground-0.27.1.dist-info}/LICENSE +0 -0
  47. {geo_activity_playground-0.26.3.dist-info → geo_activity_playground-0.27.1.dist-info}/WHEEL +0 -0
  48. {geo_activity_playground-0.26.3.dist-info → geo_activity_playground-0.27.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,74 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <div class="row">
5
+ <div class="col">
6
+ <h1>Settings</h1>
7
+ </div>
8
+ </div>
9
+
10
+ <p>Here are various settings that control how activities are gathered, analyzed and visualized.</p>
11
+
12
+ <div class="row mb-3">
13
+ <div class="row row-cols-1 row-cols-md-3 g-3">
14
+ <div class="col">
15
+ <div class="card">
16
+ <div class="card-body">
17
+ <h5 class="card-title">Equipment offsets</h5>
18
+ <p class="card-text">Not all activities with a given equipment are recorded? Just set an offset.</p>
19
+ <a href="{{ url_for('.equipment_offsets') }}" class="btn btn-primary">Set up equipment offsets</a>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ <div class="col">
24
+ <div class="card">
25
+ <div class="card-body">
26
+ <h5 class="card-title">Heart rate</h5>
27
+ <p class="card-text">Specify maximum heart rate to derive heart rate zones.</p>
28
+ <a href="{{ url_for('.heart_rate') }}" class="btn btn-primary">Set up heart rate</a>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ <div class="col">
33
+ <div class="card">
34
+ <div class="card-body">
35
+ <h5 class="card-title">Kinds without achievements</h5>
36
+ <p class="card-text">Recorded car rides that shouldn't count towards the explorer tiles? Exempt
37
+ activity kinds from consideration.</p>
38
+ <a href="{{ url_for('.kinds_without_achievements') }}" class="btn btn-primary">Set up kinds without
39
+ achievements</a>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ <div class="col">
44
+ <div class="card">
45
+ <div class="card-body">
46
+ <h5 class="card-title">Metadata extraction</h5>
47
+ <p class="card-text">When using activity files, one might want to extract metadata from the paths or
48
+ set defaults.</p>
49
+ <a href="{{ url_for('.metadata_extraction') }}" class="btn btn-primary">Set up metadata
50
+ extraction</a>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ <div class="col">
55
+ <div class="card">
56
+ <div class="card-body">
57
+ <h5 class="card-title">Privacy zones</h5>
58
+ <p class="card-text">Define geographic zones that shall be excluded from share pictures.</p>
59
+ <a href="{{ url_for('.privacy_zones') }}" class="btn btn-primary">Set up privacy zones</a>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ <div class="col">
64
+ <div class="card">
65
+ <div class="card-body">
66
+ <h5 class="card-title">Strava API</h5>
67
+ <p class="card-text">Connect to the Strava API to download activities from there.</p>
68
+ <a href="{{ url_for('.strava') }}" class="btn btn-primary">Set up Strava API</a>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ {% endblock %}
@@ -0,0 +1,30 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+
5
+ <h1 class="mb-3">Kinds without Achievements</h1>
6
+
7
+ <p>Apart from bicycle rides and runs, you might also record your car and train rides. If you don't want to include these
8
+ for achievements like explorer tiles, you can enter the activity kinds that should not be considered here.</p>
9
+
10
+ <form method="POST">
11
+ <div class="row">
12
+ <div class="col-md-6">
13
+ {% for kind in kinds_without_achievements %}
14
+ <div class="mb-3">
15
+ <label for="kind_{{ loop.index }}" class="form-label">Kind</label>
16
+ <input type="text" class="form-control" id="kind_{{ loop.index }}" name="kind" value="{{ kind }}" />
17
+ </div>
18
+ {% endfor %}
19
+ <div class="mb-3">
20
+ <label for="regex_new" class="form-label">Kind</label>
21
+ <input type="text" class="form-control" id="kind_new" name="kind" />
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ <button type="submit" class="btn btn-primary">Save</button>
27
+ </form>
28
+
29
+
30
+ {% endblock %}
@@ -0,0 +1,55 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+
5
+ <h1 class="mb-3">Metadata Extraction</h1>
6
+
7
+ <p>There are a few metadata fields that can be populated with information from the path of the activity file or by a
8
+ default value. These are:</p>
9
+
10
+ <ul>
11
+ <li><tt>kind</tt>: The kind of the activity, like "Ride" or "Run".</li>
12
+ <li><tt>equipment</tt>: Name for the equipment used, like "Red Roadbike".</li>
13
+ <li><tt>name</tt>: Name for the activity, like "Ride with Friends".</li>
14
+ </ul>
15
+
16
+ <p>By default these fields are populated with information from within the activity files. In case one hasn't set these
17
+ values correctly, it can be nice to override this data.</p>
18
+
19
+ <form method="POST">
20
+ <div class="row">
21
+ <div class="col-md-6">
22
+ {% for regex in metadata_extraction_regexes %}
23
+ <div class="mb-3">
24
+ <label for="regex_{{ loop.index }}" class="form-label">Regular expression</label>
25
+ <input type="text" class="form-control" id="regex_{{ loop.index }}" name="regex" value="{{ regex }}" />
26
+ </div>
27
+ {% endfor %}
28
+ <div class="mb-3">
29
+ <label for="regex_new" class="form-label">Regular expression</label>
30
+ <input type="text" class="form-control" id="regex_new" name="regex" />
31
+ </div>
32
+ </div>
33
+
34
+ <div class="col-md-6">
35
+ <p>To give an example of what is possible, consider a directory structure where we have
36
+ <tt>{kind}/{equipment}/{date} {name}.{ext}</tt>. Such an activity could be <tt>Ride/Red
37
+ Roadbike/2024-08-10 11-45-00 Ride with Friends.fit</tt>. In order to extract this, we could use the
38
+ following regular expression:
39
+ </p>
40
+
41
+ <div class="code">
42
+ <pre
43
+ class="code literal-block">(?P&lt;kind&gt;[^/]+)/(?P&lt;equipment&gt;[^/]+)/[-\d_ .]+(?P&lt;name&gt;[^/\.]+)</pre>
44
+ </div>
45
+
46
+ <p>This uses "capture groups". Have a look at the <a href="https://docs.python.org/3/library/re.html">Python
47
+ regex documentation</a> if you want to build your own.</p>
48
+ </div>
49
+ </div>
50
+
51
+ <button type="submit" class="btn btn-primary">Save</button>
52
+ </form>
53
+
54
+
55
+ {% endblock %}
@@ -0,0 +1,81 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+
5
+ <h1 class="mb-3">Privacy Zones</h1>
6
+
7
+ <p>You might want to remove points that are close to your home, work or relatives. For this you can define
8
+ arbitrary polygons as "privacy zones". Go to <a href="https://geojson.io/" target="_blank">GeoJSON.io</a> to have a
9
+ nice interactive tool for creating overlays. Create a single polygon, rectangle or circle to define a privacy zone.
10
+ You can define as many zones as you want, but each zone must only consist of a single area. When you are done, copy
11
+ the JSON output from the left into the text box below.</p>
12
+
13
+ <p>You can change the name on an existing privacy zone. To delete a zone, delete the name or the GeoJSON. Zones without
14
+ a name will be deleted.</p>
15
+
16
+ <script>
17
+ function add_map(id, geojson) {
18
+ let map = L.map(`map-${id}`, {
19
+ fullscreenControl: true
20
+ })
21
+ L.tileLayer('/tile/color/{z}/{x}/{y}.png', {
22
+ maxZoom: 19,
23
+ attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
24
+ }).addTo(map)
25
+
26
+ let geojson_layer = L.geoJSON(geojson).addTo(map)
27
+ map.fitBounds(geojson_layer.getBounds())
28
+ return map
29
+ }
30
+ </script>
31
+
32
+
33
+
34
+ <form method="POST">
35
+ {% if privacy_zones %}
36
+ <h2 class="mb-3">Existing zones</h2>
37
+
38
+ <div class="row row-cols-1 row-cols-md-3 g-4 mb-3">
39
+ {% for zone_name, zone_geojson in privacy_zones.items() %}
40
+
41
+ <div class="col-md-4">
42
+ <div class="mb-3">
43
+ <label for="zone_name_{{ loop.index }}" class="form-label">Name</label>
44
+ <input type="text" class="form-control" id="zone_name_{{ loop.index }}" name="zone_name"
45
+ value="{{ zone_name }}" />
46
+ </div>
47
+ <div class="mb-3">
48
+ <label for="zone_geojson_{{ loop.index }}" class="form-label">GeoJSON</label>
49
+ <textarea class="form-control" id="zone_geojson_{{ loop.index }}" name="zone_geojson"
50
+ rows="10">{{ zone_geojson|tojson(indent=2) }}</textarea>
51
+ </div>
52
+ <div class="card-img-top" id="map-{{ loop.index }}" style="height: 300px; width: 100%;"></div>
53
+ <script>
54
+ let map{{ loop.index }} = add_map("{{ loop.index }}", {{ zone_geojson | safe }})
55
+ </script>
56
+ </div>
57
+ {% endfor %}
58
+ </div>
59
+ {% endif %}
60
+
61
+ <h2 class="mb-3">New zone</h2>
62
+
63
+ <div class="row mb-3">
64
+ <div class="col-md-4">
65
+ <div class="mb-3">
66
+ <label for="new_zone_name" class="form-label">Name</label>
67
+ <input type="text" class="form-control" id="new_zone_name" name="zone_name" />
68
+ </div>
69
+ <div class="mb-3">
70
+ <label for="new_zone_geojson" class="form-label">GeoJSON</label>
71
+ <textarea class="form-control" id="new_zone_geojson" name="zone_geojson" rows="10"></textarea>
72
+ </div>
73
+
74
+ </div>
75
+ </div>
76
+
77
+ <button type="submit" class="btn btn-primary">Save</button>
78
+ </form>
79
+
80
+
81
+ {% endblock %}
@@ -13,21 +13,31 @@
13
13
  button. If you don't want to share the API limits with other people, go the <a
14
14
  href="https://www.strava.com/settings/api">Strava API page</a> and create your own app. Then fill in
15
15
  "client ID" and "client secret" in the form.</p>
16
+
17
+ <p>
18
+ Status:
19
+ {% if strava_client_code %}
20
+ <span class="badge text-bg-success">Connected</span>
21
+ {% else %}
22
+ <span class="badge text-bg-secondary">Not connected</span>
23
+ {% endif %}
24
+ </p>
16
25
  </div>
17
26
 
18
27
  <div class="col-md-6">
19
- <form action="/strava/post-client-id" method="POST">
28
+ <form action="" method="POST">
20
29
  <div class="mb-3">
21
- <label for="client_id" class="form-label">Client ID</label>
22
- <input type="text" class="form-control" id="client_id" name="client_id" value="131693" />
30
+ <label for="strava_client_id" class="form-label">Client ID</label>
31
+ <input type="text" class="form-control" id="strava_client_id" name="strava_client_id"
32
+ value="{{ strava_client_id }}" />
23
33
  </div>
24
34
  <div class="mb-3">
25
- <label for="client_secret" class="form-label">Client Secret</label>
26
- <input type="text" class="form-control" id="client_secret" name="client_secret"
27
- value="0ccc0100a2c218512a7ef0cea3b0e322fb4b4365" />
35
+ <label for="strava_client_secret" class="form-label">Client Secret</label>
36
+ <input type="text" class="form-control" id="strava_client_secret" name="strava_client_secret"
37
+ value="{{ strava_client_secret }}" />
28
38
  </div>
29
39
 
30
- <input type="submit" value="Connect to Strava" />
40
+ <button type="submit" class="btn btn-primary">Connect to Strava</button>
31
41
  </form>
32
42
  </div>
33
43
  </div>
@@ -66,7 +66,7 @@
66
66
  {% endfor %}
67
67
  {% else %}
68
68
  <p>You don't have activities yet. Either put some files into a directory <tt>Activities</tt> or <a
69
- href="{{ url_for('strava.setup') }}">set up Strava API</a>.</p>
69
+ href="{{ url_for('settings.strava') }}">set up Strava API</a>.</p>
70
70
  {% endif %}
71
71
 
72
72
  {% endblock %}
@@ -60,6 +60,7 @@
60
60
  </button>
61
61
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
62
62
  <ul class="navbar-nav me-auto mb-2 mb-lg-0">
63
+
63
64
  {% if num_activities > 0 %}
64
65
  <li class="nav-item">
65
66
  <a class="nav-link" aria-current="page" href="{{ url_for('summary.index') }}">Summary</a>
@@ -91,7 +92,10 @@
91
92
  <a class="nav-link" aria-current="page" href="{{ url_for('upload.index') }}">Upload</a>
92
93
  </li>
93
94
  <li class="nav-item">
94
- <a class="nav-link" aria-current="page" href="{{ url_for('settings') }}">Settings</a>
95
+ <a class="nav-link" aria-current="page" href="{{ url_for('upload.reload') }}">Refresh</a>
96
+ </li>
97
+ <li class="nav-item">
98
+ <a class="nav-link" aria-current="page" href="{{ url_for('settings.index') }}">Settings</a>
95
99
  </li>
96
100
 
97
101
 
@@ -4,12 +4,13 @@ from flask import render_template
4
4
  from ...core.activities import ActivityRepository
5
5
  from ...explorer.tile_visits import TileVisitAccessor
6
6
  from .controller import UploadController
7
+ from geo_activity_playground.core.config import Config
7
8
 
8
9
 
9
10
  def make_upload_blueprint(
10
11
  repository: ActivityRepository,
11
12
  tile_visit_accessor: TileVisitAccessor,
12
- config: dict,
13
+ config: Config,
13
14
  ) -> Blueprint:
14
15
  blueprint = Blueprint("upload", __name__, template_folder="templates")
15
16
 
@@ -25,4 +26,12 @@ def make_upload_blueprint(
25
26
  def receive():
26
27
  return upload_controller.receive()
27
28
 
29
+ @blueprint.route("/refresh")
30
+ def reload():
31
+ return render_template("upload/reload.html.j2")
32
+
33
+ @blueprint.route("/execute-reload")
34
+ def execute_reload():
35
+ return upload_controller.execute_reload()
36
+
28
37
  return blueprint
@@ -1,18 +1,18 @@
1
1
  import logging
2
2
  import os
3
3
  import pathlib
4
- import sys
5
4
 
6
5
  from flask import flash
7
6
  from flask import redirect
8
7
  from flask import request
9
8
  from flask import Response
9
+ from flask import url_for
10
10
  from werkzeug.utils import secure_filename
11
11
 
12
12
  from geo_activity_playground.core.activities import ActivityRepository
13
13
  from geo_activity_playground.core.activities import build_activity_meta
14
+ from geo_activity_playground.core.config import Config
14
15
  from geo_activity_playground.core.enrichment import enrich_activities
15
- from geo_activity_playground.core.paths import _strava_dynamic_config_path
16
16
  from geo_activity_playground.explorer.tile_visits import compute_tile_evolution
17
17
  from geo_activity_playground.explorer.tile_visits import compute_tile_visits
18
18
  from geo_activity_playground.explorer.tile_visits import TileVisitAccessor
@@ -32,7 +32,7 @@ class UploadController:
32
32
  self,
33
33
  repository: ActivityRepository,
34
34
  tile_visit_accessor: TileVisitAccessor,
35
- config: dict,
35
+ config: Config,
36
36
  ) -> None:
37
37
  self._repository = repository
38
38
  self._tile_visit_accessor = tile_visit_accessor
@@ -45,7 +45,7 @@ class UploadController:
45
45
  directories.sort()
46
46
  return {
47
47
  "directories": directories,
48
- "has_upload": "password" in self._config.get("upload", {}),
48
+ "has_upload": self._config.upload_password,
49
49
  }
50
50
 
51
51
  def receive(self) -> Response:
@@ -54,7 +54,7 @@ class UploadController:
54
54
  flash("No file could be found. Did you select a file?", "warning")
55
55
  return redirect("/upload")
56
56
 
57
- if request.form["password"] != self._config["upload"]["password"]:
57
+ if request.form["password"] != self._config.upload_password:
58
58
  flash("Incorrect upload password!", "danger")
59
59
  return redirect("/upload")
60
60
 
@@ -88,24 +88,37 @@ class UploadController:
88
88
  flash(f"Activity was saved with ID {activity_id}.", "success")
89
89
  return redirect(f"/activity/{activity_id}")
90
90
 
91
+ def execute_reload(self) -> None:
92
+ scan_for_activities(
93
+ self._repository,
94
+ self._tile_visit_accessor,
95
+ self._config,
96
+ skip_strava=True,
97
+ )
98
+ flash("Scanned for new activities.", category="success")
99
+ return redirect(url_for("index"))
100
+
91
101
 
92
102
  def scan_for_activities(
93
103
  repository: ActivityRepository,
94
104
  tile_visit_accessor: TileVisitAccessor,
95
- config: dict,
105
+ config: Config,
96
106
  skip_strava: bool = False,
97
107
  ) -> None:
98
108
  if pathlib.Path("Activities").exists():
99
- import_from_directory(config.get("metadata_extraction_regexes", []))
109
+ import_from_directory(
110
+ config.metadata_extraction_regexes,
111
+ config.num_processes,
112
+ )
100
113
  if pathlib.Path("Strava Export").exists():
101
114
  import_from_strava_checkout()
102
- if (_strava_dynamic_config_path.exists() or "strava" in config) and not skip_strava:
103
- import_from_strava_api()
115
+ if config.strava_client_code and not skip_strava:
116
+ import_from_strava_api(config)
104
117
 
105
- enrich_activities(config.get("kind", {}))
118
+ enrich_activities(config)
106
119
  build_activity_meta()
107
120
  repository.reload()
108
121
 
109
122
  if len(repository) > 0:
110
123
  compute_tile_visits(repository, tile_visit_accessor)
111
- compute_tile_evolution(tile_visit_accessor)
124
+ compute_tile_evolution(tile_visit_accessor, config)
@@ -0,0 +1,16 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+ <h1>Reloading</h1>
5
+
6
+ <p>Checking for new activities, importing them and adding them to the database. This might take a while …</p>
7
+
8
+ <div class="progress" role="progressbar" aria-label="Animated striped example" aria-valuenow="100" aria-valuemin="0"
9
+ aria-valuemax="100">
10
+ <div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 100%"></div>
11
+ </div>
12
+
13
+ <script type="text/javascript">
14
+ window.location.replace("{{ url_for('.execute_reload') }}");
15
+ </script>
16
+ {% endblock %}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geo-activity-playground
3
- Version: 0.26.3
3
+ Version: 0.27.1
4
4
  Summary: Analysis of geo data activities like rides, runs or hikes.
5
5
  License: MIT
6
6
  Author: Martin Ueding
@@ -1,39 +1,42 @@
1
1
  geo_activity_playground/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- geo_activity_playground/__main__.py,sha256=NQDFaa1BSIdare1oIdYO0cESf0kPVnEIE3J24jlsX_E,4021
2
+ geo_activity_playground/__main__.py,sha256=0feB3cw3-U9q0Dkrn5co76gTPpwGRWyfI5mfWNSZ_lU,4063
3
3
  geo_activity_playground/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- geo_activity_playground/core/activities.py,sha256=I1lsn1gO_P9eHbZCZlkCO6Lvi5sqXq_-c-1aDv6uKMs,8081
5
- geo_activity_playground/core/config.py,sha256=YjqCiEmIAa-GM1-JfBctMEsl8-I56pZyyDdTyPduOzw,477
4
+ geo_activity_playground/core/activities.py,sha256=Z81Itv3qrokxE1-YnPrDJ0QteyBZYjQYvTP-tHvR9j4,6606
5
+ geo_activity_playground/core/config.py,sha256=Ogv_nPJD3ihlgBDZsCv5XsWAUXIKKhzWR6cu-KMNMWU,4414
6
6
  geo_activity_playground/core/coordinates.py,sha256=tDfr9mlXhK6E_MMIJ0vYWVCoH0Lq8uyuaqUgaa8i0jg,966
7
- geo_activity_playground/core/enrichment.py,sha256=CIkUS_wtLJ8ZLwtzxsZ8gRn8mkITLwIwq3AzTxZ-kzI,6994
7
+ geo_activity_playground/core/enrichment.py,sha256=CwZhW-svgPAYbdx3n9kvKlTgcsiCaeuJfSRCC4JxX6g,7411
8
+ geo_activity_playground/core/heart_rate.py,sha256=IwMt58TpjOYqpAxtsj07zP2ttpN_J3GZeiv-qGhYyJc,1598
8
9
  geo_activity_playground/core/heatmap.py,sha256=bRLQHzmTEsQbX8XWeg85x_lRGk272UoYRiCnoxZ5da0,4189
9
- geo_activity_playground/core/paths.py,sha256=ohJN_xNLh303uc0ATpL4iH01xANIE86pILRaQi4e-RQ,1893
10
+ geo_activity_playground/core/paths.py,sha256=AiYUJv46my_FGYbHZmSs5ZrqeE65GNdWEMmXZgunZrk,2150
10
11
  geo_activity_playground/core/privacy_zones.py,sha256=4TumHsVUN1uW6RG3ArqTXDykPVipF98DCxVBe7YNdO8,512
11
12
  geo_activity_playground/core/similarity.py,sha256=Jo8jRViuORCxdIGvyaflgsQhwu9S_jn10a450FRL18A,3159
12
- geo_activity_playground/core/tasks.py,sha256=22rIidyRR0eDqz9T7swJJSl7I96OeZ-T6xFQkh1-RsQ,2521
13
+ geo_activity_playground/core/tasks.py,sha256=k_DHzY--V5EHqMh-aNFh-VsLiQntvAsGbmK5zZJ0YPI,2909
13
14
  geo_activity_playground/core/test_tiles.py,sha256=zce1FxNfsSpOQt66jMehdQRVoNdl-oiFydx6iVBHZXM,764
14
15
  geo_activity_playground/core/test_time_conversion.py,sha256=Sh6nZA3uCTOdZTZa3yOijtR0m74QtZu2mcWXsDNnyQI,984
15
- geo_activity_playground/core/tiles.py,sha256=VxPu9vdfKnxDxaYo5JSYmka9Dt3TDxg0zo3cYVJXVHc,3359
16
+ geo_activity_playground/core/tiles.py,sha256=KpzD-h3kNzZ2ieLt6f2xHilSF3lHyfaEXPnrGvlIAz0,3379
16
17
  geo_activity_playground/core/time_conversion.py,sha256=9J6aTlqJhWvsknQkoECNL-CIG-8BKs6ZatJJ9XJnTsg,367
17
18
  geo_activity_playground/explorer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
19
  geo_activity_playground/explorer/grid_file.py,sha256=k6j6KBEk2a2BY-onE8SV5TJsERGGyOrlY4as__meWpA,3304
19
- geo_activity_playground/explorer/tile_visits.py,sha256=CLZ8bCUKc5YoxvNa23hGF9JtlinIl9Wbk9u2xN4bJpw,13457
20
+ geo_activity_playground/explorer/tile_visits.py,sha256=p0MK0V4fHhroR-FN8S9m5nW0vT7uO39Euo-_mOw0Q8k,13586
20
21
  geo_activity_playground/explorer/video.py,sha256=ROAmV9shfJyqTgnXVD41KFORiwnRgVpEWenIq4hMCRM,4389
21
22
  geo_activity_playground/importers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
23
  geo_activity_playground/importers/activity_parsers.py,sha256=m2SpvGlTZ8F3gG6YB24_ZFrlOAbtqbfWi-GIYspeUco,10593
23
- geo_activity_playground/importers/directory.py,sha256=YTYuroH-oYviL2a9B7No-6Fx4RrkhMqf60Yh-7dGats,5384
24
- geo_activity_playground/importers/strava_api.py,sha256=ihy_ezq_gYUy1V4jbtg41N6K0ilYVOEiPZE07lSiUHU,8444
25
- geo_activity_playground/importers/strava_checkout.py,sha256=gOmqwDJE2kP6KFwxJ8_zGn5kcEcRqnfOqw8jJ4eHcaU,8596
24
+ geo_activity_playground/importers/csv_parser.py,sha256=7x0U4MyKNCsVFnXU6US8FQ28X9PTIoQS8U_hzF5l4So,2147
25
+ geo_activity_playground/importers/directory.py,sha256=lJVSAZpq8NAIjVQuCiVxPSNt9m_rIY0yJlOOMB-ZTG0,5746
26
+ geo_activity_playground/importers/strava_api.py,sha256=pgWZp-cWOLkvlDE85lTiEKM8BCZYzOlAAdKoa2F7c6o,7780
27
+ geo_activity_playground/importers/strava_checkout.py,sha256=N-uGTkhBJMC7cPYjRRXHOSLwpK3wc6aaSrY2RQfSitA,9419
28
+ geo_activity_playground/importers/test_csv_parser.py,sha256=LXqva7GuSAfXYE2zZQrg-69lCtfy5MxLSq6BRwL_VyI,1191
26
29
  geo_activity_playground/importers/test_directory.py,sha256=ljXokx7q0OgtHvEdHftcQYEmZJUDVv3OOF5opklxdT4,724
27
30
  geo_activity_playground/importers/test_strava_api.py,sha256=4vX7wDr1a9aRh8myxNrIq6RwDBbP8ZeoXXPc10CAbW4,431
28
31
  geo_activity_playground/webui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
32
  geo_activity_playground/webui/activity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- geo_activity_playground/webui/activity/blueprint.py,sha256=gGMes5ycXi2rMixVYs4NQgzTU1Vttgu50prYAe3--Hs,1749
31
- geo_activity_playground/webui/activity/controller.py,sha256=BSmHwO2GLyMGiFRQ0BpTsHMKDWJbz5UHnwQ9HVULN4c,16679
33
+ geo_activity_playground/webui/activity/blueprint.py,sha256=upQzZa5sKApj_Fmu6PziFDboi7SBL5Zsi-tNSSNPlEE,1759
34
+ geo_activity_playground/webui/activity/controller.py,sha256=VJrbUD2oofESV2imNr7LBrx6jhSA8miuwnrERPsUuQc,17573
32
35
  geo_activity_playground/webui/activity/templates/activity/day.html.j2,sha256=r3qKl9uTzOko4R-ZzyYAZt1j61JSevYP4g0Yi06HHPg,2702
33
36
  geo_activity_playground/webui/activity/templates/activity/lines.html.j2,sha256=5gB1aDjRgi_RventenRfC10_FtMT4ch_VuWvA9AMlBY,1121
34
37
  geo_activity_playground/webui/activity/templates/activity/name.html.j2,sha256=RDLEt6ip8_ngmdLgaC5jg92Dk-F2umGwKkd8cWmvVko,2400
35
- geo_activity_playground/webui/activity/templates/activity/show.html.j2,sha256=NOsMPUBy1UQM_YebtT6RQxLSgSGvCMetqi_mspJmUjQ,5229
36
- geo_activity_playground/webui/app.py,sha256=h8yc6Ls7ozE7IblCM6TFs30t6J7FoTeWATLWwp_UVQc,4117
38
+ geo_activity_playground/webui/activity/templates/activity/show.html.j2,sha256=3g-Hab06uWBPJo6DmTk4lM2OlozE1EyrQK6RgTgTuwU,5521
39
+ geo_activity_playground/webui/app.py,sha256=xKPP0WDyHMAbkpJsuEz53skIjOMRBMvueD6LpRdYJE0,4119
37
40
  geo_activity_playground/webui/calendar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
41
  geo_activity_playground/webui/calendar/blueprint.py,sha256=rlnhgU2DWAcdLMRq7m77NzrM_aDyp4s3kuuQHuzjHhg,782
39
42
  geo_activity_playground/webui/calendar/controller.py,sha256=QpSAkR2s1sbLSu6P_fNNTccgGglOzEH2PIv1XwKxeVY,2778
@@ -41,22 +44,31 @@ geo_activity_playground/webui/calendar/templates/calendar/index.html.j2,sha256=x
41
44
  geo_activity_playground/webui/calendar/templates/calendar/month.html.j2,sha256=sRIiNo_Rp9CHary6e-lnpKJKOuAonoDEBvKMxzbTLQE,1802
42
45
  geo_activity_playground/webui/eddington/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
46
  geo_activity_playground/webui/eddington/blueprint.py,sha256=evIvueLfDWVTxJ9pRguqmZ9-Pybd2WmBRst_-7vX2QA,551
44
- geo_activity_playground/webui/eddington/controller.py,sha256=L4YssL088UMamp4qgzEtilzhaKGZsyfVUScuw-fmTjE,2888
47
+ geo_activity_playground/webui/eddington/controller.py,sha256=ly7JSkSS79kO4CL_xugB62uRuuWKVqOjbN-pheelv94,2910
45
48
  geo_activity_playground/webui/eddington/templates/eddington/index.html.j2,sha256=XHKeUymQMS5x00PLOVlg-nSRCz_jHB2pvD8QunULWJ4,1839
46
49
  geo_activity_playground/webui/entry_controller.py,sha256=n9v4MriyL8kDR91LE9eeqc2tAvxyzFgoNMMXpr0qh4g,1906
47
50
  geo_activity_playground/webui/equipment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- geo_activity_playground/webui/equipment/blueprint.py,sha256=YbOAsjk05BMeUlD6wGfxE1amvlLsFjG4HMJn5SBrVRU,551
49
- geo_activity_playground/webui/equipment/controller.py,sha256=m1LNaGCNJnW97TlKT6x9NfQcMp6RKcZ8Q0I1FTUAvss,4037
51
+ geo_activity_playground/webui/equipment/blueprint.py,sha256=_NIhRJuJNbXpEd_nEPo01AqnUqPgo1vawFn7E3yoeng,636
52
+ geo_activity_playground/webui/equipment/controller.py,sha256=_iLkQeeu7UYMg7FGNemTrhm8e0pf409f9aUXnGfNsCI,4022
50
53
  geo_activity_playground/webui/equipment/templates/equipment/index.html.j2,sha256=FEfxB4XwVYELAOdjVlSlprjJH_kLmE-pNWEEXdPqc6I,1778
51
54
  geo_activity_playground/webui/explorer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- geo_activity_playground/webui/explorer/blueprint.py,sha256=jHE6bb4H2GmYaix9P452Cyrn_30z_Nm705AZ0WNm4HQ,1950
53
- geo_activity_playground/webui/explorer/controller.py,sha256=8d0FFrG55ZlPQ5seQC2DegxIkPGIW7pvw8Jm4eJt3fg,10634
54
- geo_activity_playground/webui/explorer/templates/explorer/index.html.j2,sha256=OxNt2_VwH-cmVXJrDNfeD-dNB9IrwBjdhhQEqkXxHj0,6529
55
+ geo_activity_playground/webui/explorer/blueprint.py,sha256=EKnBs8llqT6Wy1uac18dF2epp3TebF9p3iGlSbj6Vl0,2337
56
+ geo_activity_playground/webui/explorer/controller.py,sha256=M3FdPLrcP9GZiCjuRVY0ug1DtTqLvIbEDCzRHf6QuOE,11555
57
+ geo_activity_playground/webui/explorer/templates/explorer/index.html.j2,sha256=cm9pWY0vB84DtkTH-LBvSzfLU1FnmxQ2ECyw3Bl7dTo,6945
55
58
  geo_activity_playground/webui/heatmap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
59
  geo_activity_playground/webui/heatmap/blueprint.py,sha256=bjQu-HL3QN5UpJ6tHOifhcLGlPr_hIKvaRu78md4JqM,1470
57
60
  geo_activity_playground/webui/heatmap/heatmap_controller.py,sha256=i376qEqTJrhezGsdPyKR8VsRY2N0JdEra7_kY7NmwW8,6822
58
61
  geo_activity_playground/webui/heatmap/templates/heatmap/index.html.j2,sha256=YLeu6P4djl8G4qAXR6DhetseqrbOodN7aN4coocknc4,1875
59
62
  geo_activity_playground/webui/search_controller.py,sha256=PzMf7b8tiJKZIZoPvQ9A2hOrzoKV9cS3jq05w2fK94c,532
63
+ geo_activity_playground/webui/settings/blueprint.py,sha256=1u16oRlauOSPVBGBzjf08Ja9jxbqEKnwcDISWl7CmJU,4113
64
+ geo_activity_playground/webui/settings/controller.py,sha256=ixuYgpMGggg9kmcIVTgL2gzAPhYjMpqWEPxS7YXlmnA,7902
65
+ geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2,sha256=ltaYwFe8S8Mi72ddmIp1vwqlu8MEXXjBGfbpN2WBTC4,1728
66
+ geo_activity_playground/webui/settings/templates/settings/heart-rate.html.j2,sha256=UPT3MegRgSeff36lhCo0l3ZwhqNSIg5gM6h2s32GkCY,4255
67
+ geo_activity_playground/webui/settings/templates/settings/index.html.j2,sha256=26VEC_MbdIyd7vbFokDFtJelcuK3YFb1_3WaFLGv_bk,3183
68
+ geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2,sha256=IdUfXon1Pu8zX3NirKb28ypshLHOvZRpz2T4bJrzrak,1067
69
+ geo_activity_playground/webui/settings/templates/settings/metadata-extraction.html.j2,sha256=Ppa8O-zRJznbeCsF4YQj37_HM9nOW8fyTi66jvWvHmA,2285
70
+ geo_activity_playground/webui/settings/templates/settings/privacy-zones.html.j2,sha256=7BxFvCaVJOEqbImyK5vxCmhh-NGSFaRa9ARhqjZeYJ0,3093
71
+ geo_activity_playground/webui/settings/templates/settings/strava.html.j2,sha256=FrXgT-m1PgvsQWo9kMKpk8QenKeifSDBCZFqKgsHRxQ,1827
60
72
  geo_activity_playground/webui/square_planner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
73
  geo_activity_playground/webui/square_planner/blueprint.py,sha256=r2VkSM547chX85g6c1BQ8NC-tkdqGdYp-2ZALBiiDTc,1320
62
74
  geo_activity_playground/webui/square_planner/controller.py,sha256=wYcNEviDgqyYxSrnwMD_5LnYXIazVH9plGX8RxG6oco,3464
@@ -73,28 +85,23 @@ geo_activity_playground/webui/static/favicon.ico,sha256=uVNZlrF22zn1lcCS_9wAoWLh
73
85
  geo_activity_playground/webui/static/mstile-150x150.png,sha256=j1ANUQJ1Xi1DR2sGqYZztob2ypfGw04eNtGpN9SxExA,11964
74
86
  geo_activity_playground/webui/static/safari-pinned-tab.svg,sha256=OzoEVGY0igWRXM1NiM3SRKugdICBN7aB_XuxaC3Mu9Q,8371
75
87
  geo_activity_playground/webui/static/site.webmanifest,sha256=4vYxdPMpwTdB8EmOvHkkYcjZ8Yrci3pOwwY3o_VwACA,440
76
- geo_activity_playground/webui/strava/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- geo_activity_playground/webui/strava/blueprint.py,sha256=Q2Wfxlg7bR2vjWZ3UpckPl9jWHwNB8hfP7SLBufgiUY,1055
78
- geo_activity_playground/webui/strava/controller.py,sha256=Ye0R-nu5SwFdk2DAIEq7OE76XLgnRk9y8iJjLObbAUc,1437
79
- geo_activity_playground/webui/strava/templates/strava/client-id.html.j2,sha256=m5gJk0VxcIn0VcROsOke5A5MbWXC5O1e1Lxc09MyN_g,1493
80
- geo_activity_playground/webui/strava/templates/strava/connected.html.j2,sha256=TN6H8YPjG2zk8fodTaSaloTEJCXnpgTCIRX_uEVTiNI,274
81
88
  geo_activity_playground/webui/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
89
  geo_activity_playground/webui/summary/blueprint.py,sha256=kzQ6MDOycQKfDcVoEUmL7HYHJA_gu8DlzVHwO37-_jA,514
83
90
  geo_activity_playground/webui/summary/controller.py,sha256=ZOrwfrKjpc8hecUYImBvesKXZi06obfR1yhQkVTeWzw,8981
84
91
  geo_activity_playground/webui/summary/templates/summary/index.html.j2,sha256=rsII1eMY-xNugh8A9SecnEcDZqkEOWYIfiHAGroQYuM,4442
85
- geo_activity_playground/webui/templates/home.html.j2,sha256=fp48MjBuO4QJfQz6YPOWH56IzStgaclx9XbwEKmUFHQ,2403
86
- geo_activity_playground/webui/templates/page.html.j2,sha256=RyB-G2dhdhTUSwXAxquylk2ma3DXMZ490g6yrgsxA-I,9388
92
+ geo_activity_playground/webui/templates/home.html.j2,sha256=FjEwr9kt_3qu_evIHpa7F_oGAINN8W2Z1T_j56ugJ5c,2406
93
+ geo_activity_playground/webui/templates/page.html.j2,sha256=sqerdJLOIcgMtQy533kHPD9uVIxF3v6ItLQSjuoCqlI,9589
87
94
  geo_activity_playground/webui/templates/search.html.j2,sha256=FvNRoDfUlSzXjM_tqZY_fDhuhUDgbPaY73q56gdvF1A,1130
88
- geo_activity_playground/webui/templates/settings.html.j2,sha256=-q9GflrG2t6kSt-NerBN5NV1gRp12JT3KgGp_aPaKT8,674
89
95
  geo_activity_playground/webui/tile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
96
  geo_activity_playground/webui/tile/blueprint.py,sha256=cK0o2Z3BrLycgF9zw0F8s9qF-JaYDbF5Gog-GXDtUZ8,943
91
97
  geo_activity_playground/webui/tile/controller.py,sha256=PISh4vKs27b-LxFfTARtr5RAwHFresA1Kw1MDcERSRU,1221
92
98
  geo_activity_playground/webui/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
- geo_activity_playground/webui/upload/blueprint.py,sha256=2l5q1LYtjgLF_3CAyPvCLx-wMebp14OJvgZBzGILdmQ,801
94
- geo_activity_playground/webui/upload/controller.py,sha256=BWcSlLy_fVAodDlnXkxE4eIotC_UHrjldACrToA-iAQ,3975
99
+ geo_activity_playground/webui/upload/blueprint.py,sha256=qU6ZKOrhB8DA8GSbOECVu2fPKd2VtBFp0mEFzjJAgIA,1083
100
+ geo_activity_playground/webui/upload/controller.py,sha256=8Xv9JMeTyPe6mhYiDBW_nv9W_Hp7yz4Cgv_lXbM_JfY,4271
95
101
  geo_activity_playground/webui/upload/templates/upload/index.html.j2,sha256=hfXkEXaz_MkM46rU56423D6V6WtK-EAXPszSY-_-Tx8,1471
96
- geo_activity_playground-0.26.3.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
97
- geo_activity_playground-0.26.3.dist-info/METADATA,sha256=9v9y9sR7bMNsUoFDrYQC9d-YQ0VL0UDVHhM6RY4I0iA,1665
98
- geo_activity_playground-0.26.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
99
- geo_activity_playground-0.26.3.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
100
- geo_activity_playground-0.26.3.dist-info/RECORD,,
102
+ geo_activity_playground/webui/upload/templates/upload/reload.html.j2,sha256=YZWX5eDeNyqKJdQAywDBcU8DZBm22rRBbZqFjrFrCvQ,556
103
+ geo_activity_playground-0.27.1.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
104
+ geo_activity_playground-0.27.1.dist-info/METADATA,sha256=Wm7WbQhD76zAw6Vf127jOm7ZeYPy0hllY9DZTKeh8oE,1665
105
+ geo_activity_playground-0.27.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
106
+ geo_activity_playground-0.27.1.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
107
+ geo_activity_playground-0.27.1.dist-info/RECORD,,
File without changes