geo-activity-playground 1.1.0__tar.gz → 1.3.0__tar.gz
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.
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/PKG-INFO +7 -3
- geo_activity_playground-1.3.0/geo_activity_playground/alembic/versions/85fe0348e8a2_add_time_series_uuid_field.py +28 -0
- geo_activity_playground-1.3.0/geo_activity_playground/alembic/versions/f2f50843be2d_make_all_fields_in_activity_nullable.py +34 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/coordinates.py +12 -1
- geo_activity_playground-1.3.0/geo_activity_playground/core/copernicus_dem.py +95 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/datamodel.py +78 -22
- geo_activity_playground-1.3.0/geo_activity_playground/core/enrichment.py +274 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/paths.py +8 -0
- geo_activity_playground-1.3.0/geo_activity_playground/core/test_pandas_timezone.py +36 -0
- geo_activity_playground-1.3.0/geo_activity_playground/core/test_time_zone_from_location.py +7 -0
- geo_activity_playground-1.3.0/geo_activity_playground/core/test_time_zone_import.py +93 -0
- geo_activity_playground-1.3.0/geo_activity_playground/core/test_timezone_sqlalchemy.py +44 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/tiles.py +4 -1
- geo_activity_playground-1.3.0/geo_activity_playground/core/time_conversion.py +42 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/explorer/tile_visits.py +7 -4
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/activity_parsers.py +21 -22
- geo_activity_playground-1.3.0/geo_activity_playground/importers/directory.py +100 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/strava_api.py +53 -36
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/strava_checkout.py +30 -56
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/app.py +40 -2
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/activity_blueprint.py +13 -11
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/entry_views.py +1 -1
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/explorer_blueprint.py +1 -7
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/heatmap_blueprint.py +2 -2
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/photo_blueprint.py +65 -56
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/settings_blueprint.py +20 -14
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/summary_blueprint.py +6 -6
- geo_activity_playground-1.3.0/geo_activity_playground/webui/blueprints/time_zone_fixer_blueprint.py +69 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/upload_blueprint.py +3 -16
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/columns.py +9 -1
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/show.html.j2 +3 -1
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/equipment/index.html.j2 +3 -3
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/hall_of_fame/index.html.j2 +2 -3
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/home.html.j2 +4 -10
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/page.html.j2 +2 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/photo/new.html.j2 +1 -1
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/index.html.j2 +9 -0
- geo_activity_playground-1.3.0/geo_activity_playground/webui/templates/settings/tile-source.html.j2 +33 -0
- geo_activity_playground-1.3.0/geo_activity_playground/webui/templates/time_zone_fixer/index.html.j2 +31 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/pyproject.toml +7 -2
- geo_activity_playground-1.1.0/geo_activity_playground/core/enrichment.py +0 -212
- geo_activity_playground-1.1.0/geo_activity_playground/core/test_time_conversion.py +0 -37
- geo_activity_playground-1.1.0/geo_activity_playground/core/time_conversion.py +0 -14
- geo_activity_playground-1.1.0/geo_activity_playground/importers/directory.py +0 -146
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/LICENSE +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/__main__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/README +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/env.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/script.py.mako +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/0f02b92c4f94_add_tag_color.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/93cc82ad1b60_add_parametricplotspec.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/da2cba03b71d_add_photos.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/dc8073871da7_add_plotspec_group_by.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/alembic/versions/script.py.mako +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/activities.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/config.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/export.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/heart_rate.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/meta_search.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/missing_values.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/parametric_plot.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/privacy_zones.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/raster_map.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/similarity.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/summary_stats.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/tasks.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/test_datamodel.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/test_meta_search.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/test_missing_values.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/test_summary_stats.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/core/test_tiles.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/explorer/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/explorer/grid_file.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/explorer/video.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/heatmap_video.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/csv_parser.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/test_csv_parser.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/test_directory.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/importers/test_strava_api.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/authenticator.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/__init__.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/auth_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/calendar_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/eddington_blueprints.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/equipment_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/export_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/search_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/square_planner_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/blueprints/tile_blueprint.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/flasher.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/plot_util.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/search_util.py +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/bootstrap/bootstrap-dark-mode.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/bootstrap/bootstrap.bundle.min.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/bootstrap/bootstrap.min.css +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/android-chrome-192x192.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/android-chrome-512x512.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/apple-touch-icon.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/browserconfig.xml +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/favicon-16x16.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/favicon-32x32.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/favicon-48x48.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/favicon.ico +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/favicon.svg +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/mstile-150x150.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/site.webmanifest +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/web-app-manifest-192x192.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/favicons/web-app-manifest-512x512.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/images/layers-2x.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/images/layers.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/images/marker-icon.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/Leaflet.fullscreen.min.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/MarkerCluster.Default.css +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/MarkerCluster.css +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/fullscreen.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/fullscreen@2x.png +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/leaflet.css +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/leaflet.fullscreen.css +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/leaflet.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/leaflet/leaflet.markercluster.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/server-side-explorer.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/table-sort.min.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/vega/vega-embed@6.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/vega/vega-lite@4.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/static/vega/vega@5.js +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/day.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/edit.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/lines.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/name.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/activity/trim.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/auth/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/calendar/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/calendar/month.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/eddington/distance.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/explorer/server-side.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/export/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/heatmap/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/photo/map.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/plot-macros.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/plot_builder/edit.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/plot_builder/import-spec.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/plot_builder/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/search/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/search_form.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/admin-password.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/color-schemes.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/heart-rate.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/metadata-extraction.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/privacy-zones.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/segmentation.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/sharepic.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/strava.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/tags-edit.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/tags-list.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/settings/tags-new.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/square_planner/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/summary/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/summary/vega-chart.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/upload/index.html.j2 +0 -0
- {geo_activity_playground-1.1.0 → geo_activity_playground-1.3.0}/geo_activity_playground/webui/templates/upload/reload.html.j2 +0 -0
@@ -1,14 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: geo-activity-playground
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: Analysis of geo data activities like rides, runs or hikes.
|
5
5
|
License: MIT
|
6
6
|
Author: Martin Ueding
|
7
7
|
Author-email: mu@martin-ueding.de
|
8
|
-
Requires-Python: >=3.
|
8
|
+
Requires-Python: >=3.11,<3.14
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
12
11
|
Classifier: Programming Language :: Python :: 3.11
|
13
12
|
Classifier: Programming Language :: Python :: 3.12
|
14
13
|
Classifier: Programming Language :: Python :: 3.13
|
@@ -16,6 +15,7 @@ Requires-Dist: Pillow (>=11.0.0,<12.0.0)
|
|
16
15
|
Requires-Dist: alembic (>=1.15.2,<2.0.0)
|
17
16
|
Requires-Dist: altair (>=5.5.0,<6.0.0)
|
18
17
|
Requires-Dist: appdirs (>=1.4.4,<2.0.0)
|
18
|
+
Requires-Dist: boto3 (>=1.38.45,<2.0.0)
|
19
19
|
Requires-Dist: charset-normalizer (>=3.3.2,<4.0.0)
|
20
20
|
Requires-Dist: coloredlogs (>=15.0.1,<16.0.0)
|
21
21
|
Requires-Dist: exifread (>=3.2.0,<4.0.0)
|
@@ -24,15 +24,19 @@ Requires-Dist: flask (>=3.0.0,<4.0.0)
|
|
24
24
|
Requires-Dist: flask-alembic (>=3.1.1,<4.0.0)
|
25
25
|
Requires-Dist: flask-sqlalchemy (>=3.1.1,<4.0.0)
|
26
26
|
Requires-Dist: geojson (>=3.0.1,<4.0.0)
|
27
|
+
Requires-Dist: geotiff (>=0.2.10,<0.3.0)
|
27
28
|
Requires-Dist: gpxpy (>=1.5.0,<2.0.0)
|
29
|
+
Requires-Dist: imagecodecs (>=2025.3.30,<2026.0.0)
|
28
30
|
Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
|
29
31
|
Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
|
32
|
+
Requires-Dist: numcodecs (<0.15.0)
|
30
33
|
Requires-Dist: numpy (>=2.2.3,<3.0.0)
|
31
34
|
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
32
35
|
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
33
36
|
Requires-Dist: pyarrow (>=19.0.1,<20.0.0)
|
34
37
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
35
38
|
Requires-Dist: requests (>=2.28.1,<3.0.0)
|
39
|
+
Requires-Dist: scipy (>=1.16.0,<2.0.0)
|
36
40
|
Requires-Dist: shapely (>=2.0.5,<3.0.0)
|
37
41
|
Requires-Dist: sqlalchemy (>=2.0.40,<3.0.0)
|
38
42
|
Requires-Dist: stravalib (>=2.0,<3.0)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from typing import Sequence
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
import sqlalchemy as sa
|
5
|
+
from alembic import op
|
6
|
+
|
7
|
+
|
8
|
+
# revision identifiers, used by Alembic.
|
9
|
+
revision: str = "85fe0348e8a2"
|
10
|
+
down_revision: Union[str, None] = "f2f50843be2d"
|
11
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
12
|
+
depends_on: Union[str, Sequence[str], None] = None
|
13
|
+
|
14
|
+
|
15
|
+
def upgrade() -> None:
|
16
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
17
|
+
with op.batch_alter_table("activities", schema=None) as batch_op:
|
18
|
+
batch_op.add_column(sa.Column("time_series_uuid", sa.String(), nullable=True))
|
19
|
+
|
20
|
+
# ### end Alembic commands ###
|
21
|
+
|
22
|
+
|
23
|
+
def downgrade() -> None:
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
25
|
+
with op.batch_alter_table("activities", schema=None) as batch_op:
|
26
|
+
batch_op.drop_column("time_series_uuid")
|
27
|
+
|
28
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from typing import Sequence
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
import sqlalchemy as sa
|
5
|
+
from alembic import op
|
6
|
+
|
7
|
+
|
8
|
+
# revision identifiers, used by Alembic.
|
9
|
+
revision: str = "f2f50843be2d"
|
10
|
+
down_revision: Union[str, None] = "dc8073871da7"
|
11
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
12
|
+
depends_on: Union[str, Sequence[str], None] = None
|
13
|
+
|
14
|
+
|
15
|
+
def upgrade() -> None:
|
16
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
17
|
+
with op.batch_alter_table("activities", schema=None) as batch_op:
|
18
|
+
batch_op.add_column(sa.Column("iana_timezone", sa.String(), nullable=True))
|
19
|
+
batch_op.add_column(sa.Column("start_country", sa.String(), nullable=True))
|
20
|
+
batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=True)
|
21
|
+
batch_op.alter_column("distance_km", existing_type=sa.FLOAT(), nullable=True)
|
22
|
+
|
23
|
+
# ### end Alembic commands ###
|
24
|
+
|
25
|
+
|
26
|
+
def downgrade() -> None:
|
27
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
28
|
+
with op.batch_alter_table("activities", schema=None) as batch_op:
|
29
|
+
batch_op.alter_column("distance_km", existing_type=sa.FLOAT(), nullable=False)
|
30
|
+
batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=False)
|
31
|
+
batch_op.drop_column("start_country")
|
32
|
+
batch_op.drop_column("iana_timezone")
|
33
|
+
|
34
|
+
# ### end Alembic commands ###
|
@@ -1,4 +1,7 @@
|
|
1
|
+
import typing
|
2
|
+
|
1
3
|
import numpy as np
|
4
|
+
import pandas as pd
|
2
5
|
|
3
6
|
|
4
7
|
class Bounds:
|
@@ -15,7 +18,15 @@ class Bounds:
|
|
15
18
|
return (self.x_min < x < self.x_max) and (self.y_min < y < self.y_max)
|
16
19
|
|
17
20
|
|
18
|
-
|
21
|
+
FloatOrSeries = typing.TypeVar("FloatOrSeries", float, np.ndarray, pd.Series)
|
22
|
+
|
23
|
+
|
24
|
+
def get_distance(
|
25
|
+
lat_1: FloatOrSeries,
|
26
|
+
lon_1: FloatOrSeries,
|
27
|
+
lat_2: FloatOrSeries,
|
28
|
+
lon_2: FloatOrSeries,
|
29
|
+
) -> FloatOrSeries:
|
19
30
|
"""
|
20
31
|
https://en.wikipedia.org/wiki/Haversine_formula
|
21
32
|
"""
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import functools
|
2
|
+
import math
|
3
|
+
import pathlib
|
4
|
+
from typing import Optional
|
5
|
+
|
6
|
+
import boto3
|
7
|
+
import botocore.config
|
8
|
+
import botocore.exceptions
|
9
|
+
import geotiff
|
10
|
+
import numpy as np
|
11
|
+
from scipy.interpolate import RegularGridInterpolator
|
12
|
+
|
13
|
+
from .paths import USER_CACHE_DIR
|
14
|
+
|
15
|
+
|
16
|
+
def s3_path(lat: int, lon: int) -> pathlib.Path:
|
17
|
+
lat_str = f"N{(lat):02d}" if lat >= 0 else f"S{(-lat):02d}"
|
18
|
+
lon_str = f"E{(lon):03d}" if lon >= 0 else f"W{(-lon):03d}"
|
19
|
+
result = (
|
20
|
+
USER_CACHE_DIR
|
21
|
+
/ "Copernicus DEM"
|
22
|
+
/ f"Copernicus_DSM_COG_30_{lat_str}_00_{lon_str}_00_DEM.tif"
|
23
|
+
)
|
24
|
+
|
25
|
+
result.parent.mkdir(exist_ok=True)
|
26
|
+
return result
|
27
|
+
|
28
|
+
|
29
|
+
def ensure_copernicus_file(p: pathlib.Path) -> None:
|
30
|
+
if p.exists():
|
31
|
+
return
|
32
|
+
s3 = boto3.client(
|
33
|
+
"s3", config=botocore.config.Config(signature_version=botocore.UNSIGNED)
|
34
|
+
)
|
35
|
+
try:
|
36
|
+
s3.download_file("copernicus-dem-90m", f"{p.stem}/{p.name}", p)
|
37
|
+
except botocore.exceptions.ClientError as e:
|
38
|
+
pass
|
39
|
+
|
40
|
+
|
41
|
+
@functools.lru_cache(9)
|
42
|
+
def get_elevation_arrays(p: pathlib.Path) -> Optional[np.ndarray]:
|
43
|
+
ensure_copernicus_file(p)
|
44
|
+
if not p.exists():
|
45
|
+
return None
|
46
|
+
gt = geotiff.GeoTiff(p)
|
47
|
+
a = np.array(gt.read())
|
48
|
+
lon_array, lat_array = gt.get_coord_arrays()
|
49
|
+
return np.stack([a, lat_array, lon_array], axis=0)
|
50
|
+
|
51
|
+
|
52
|
+
@functools.lru_cache(1)
|
53
|
+
def get_interpolator(lat: int, lon: int) -> Optional[RegularGridInterpolator]:
|
54
|
+
arrays = get_elevation_arrays(s3_path(lat, lon))
|
55
|
+
# If we don't have data for the current center, we cannot do anything.
|
56
|
+
if arrays is None:
|
57
|
+
return None
|
58
|
+
|
59
|
+
# # Take a look at the neighbors. If all 8 neighbor grid cells are present, we can
|
60
|
+
# neighbor_shapes = [
|
61
|
+
# get_elevation_arrays(s3_path(lat + lat_offset, lon + lon_offset)).shape
|
62
|
+
# for lon_offset in [-1, 0, 1]
|
63
|
+
# for lat_offset in [-1, 0, 1]
|
64
|
+
# if get_elevation_arrays(s3_path(lat + lat_offset, lon + lon_offset)) is not None
|
65
|
+
# ]
|
66
|
+
# if len(neighbor_shapes) == 9 and len(set(neighbor_shapes)) == 1:
|
67
|
+
# arrays = np.concatenate(
|
68
|
+
# [
|
69
|
+
# np.concatenate(
|
70
|
+
# [
|
71
|
+
# get_elevation_arrays(
|
72
|
+
# s3_path(lat + lat_offset, lon + lon_offset)
|
73
|
+
# )
|
74
|
+
# for lon_offset in [-1, 0, 1]
|
75
|
+
# ],
|
76
|
+
# axis=2,
|
77
|
+
# )
|
78
|
+
# for lat_offset in [1, 0, -1]
|
79
|
+
# ],
|
80
|
+
# axis=1,
|
81
|
+
# )
|
82
|
+
lat_labels = arrays[1, :, 0]
|
83
|
+
lon_labels = arrays[2, 0, :]
|
84
|
+
|
85
|
+
return RegularGridInterpolator(
|
86
|
+
(lat_labels, lon_labels), arrays[0], bounds_error=False, fill_value=None
|
87
|
+
)
|
88
|
+
|
89
|
+
|
90
|
+
def get_elevation(lat: float, lon: float) -> float:
|
91
|
+
interpolator = get_interpolator(math.floor(lat), math.floor(lon))
|
92
|
+
if interpolator is not None:
|
93
|
+
return float(interpolator((lat, lon)))
|
94
|
+
else:
|
95
|
+
return 0.0
|
@@ -1,7 +1,11 @@
|
|
1
1
|
import datetime
|
2
2
|
import json
|
3
3
|
import logging
|
4
|
+
import os
|
4
5
|
import pathlib
|
6
|
+
import shutil
|
7
|
+
import uuid
|
8
|
+
import zoneinfo
|
5
9
|
from typing import Any
|
6
10
|
from typing import Optional
|
7
11
|
from typing import TypedDict
|
@@ -32,12 +36,24 @@ logger = logging.getLogger(__name__)
|
|
32
36
|
DEFAULT_UNKNOWN_NAME = "Unknown"
|
33
37
|
|
34
38
|
|
39
|
+
def format_timedelta(v: datetime.timedelta):
|
40
|
+
if pd.isna(v):
|
41
|
+
return "—"
|
42
|
+
else:
|
43
|
+
seconds = v.total_seconds()
|
44
|
+
h = int(seconds // 3600)
|
45
|
+
m = int(seconds // 60 % 60)
|
46
|
+
s = int(seconds // 1 % 60)
|
47
|
+
return f"{h}:{m:02d}:{s:02d}"
|
48
|
+
|
49
|
+
|
35
50
|
class ActivityMeta(TypedDict):
|
36
51
|
average_speed_elapsed_kmh: float
|
37
52
|
average_speed_moving_kmh: float
|
38
53
|
calories: float
|
39
54
|
commute: bool
|
40
55
|
consider_for_achievements: bool
|
56
|
+
copernicus_elevation_gain: float
|
41
57
|
distance_km: float
|
42
58
|
elapsed_time: datetime.timedelta
|
43
59
|
elevation_gain: float
|
@@ -74,27 +90,36 @@ class Activity(DB.Model):
|
|
74
90
|
|
75
91
|
# Housekeeping data:
|
76
92
|
id: Mapped[int] = mapped_column(primary_key=True)
|
77
|
-
name: Mapped[str] = mapped_column(sa.String, nullable=
|
78
|
-
distance_km: Mapped[float] = mapped_column(sa.Float, nullable=
|
93
|
+
name: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
94
|
+
distance_km: Mapped[Optional[float]] = mapped_column(sa.Float, nullable=True)
|
95
|
+
time_series_uuid: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
79
96
|
|
80
97
|
# Where it comes from:
|
81
|
-
path: Mapped[str] = mapped_column(sa.String, nullable=True)
|
82
|
-
upstream_id: Mapped[str] = mapped_column(sa.String, nullable=True)
|
98
|
+
path: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
99
|
+
upstream_id: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
83
100
|
|
84
101
|
# Crop data:
|
85
102
|
index_begin: Mapped[int] = mapped_column(sa.Integer, nullable=True)
|
86
103
|
index_end: Mapped[int] = mapped_column(sa.Integer, nullable=True)
|
87
104
|
|
88
105
|
# Temporal data:
|
89
|
-
start: Mapped[datetime.datetime] = mapped_column(
|
90
|
-
|
91
|
-
|
106
|
+
start: Mapped[Optional[datetime.datetime]] = mapped_column(
|
107
|
+
sa.DateTime, nullable=True
|
108
|
+
)
|
109
|
+
iana_timezone: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
110
|
+
elapsed_time: Mapped[Optional[datetime.timedelta]] = mapped_column(
|
111
|
+
sa.Interval, nullable=True
|
112
|
+
)
|
113
|
+
moving_time: Mapped[Optional[datetime.timedelta]] = mapped_column(
|
114
|
+
sa.Interval, nullable=True
|
115
|
+
)
|
92
116
|
|
93
117
|
# Geographic data:
|
94
118
|
start_latitude: Mapped[float] = mapped_column(sa.Float, nullable=True)
|
95
119
|
start_longitude: Mapped[float] = mapped_column(sa.Float, nullable=True)
|
96
120
|
end_latitude: Mapped[float] = mapped_column(sa.Float, nullable=True)
|
97
121
|
end_longitude: Mapped[float] = mapped_column(sa.Float, nullable=True)
|
122
|
+
start_country: Mapped[Optional[str]] = mapped_column(sa.String, nullable=True)
|
98
123
|
|
99
124
|
# Elevation data:
|
100
125
|
elevation_gain: Mapped[float] = mapped_column(sa.Float, nullable=True)
|
@@ -132,30 +157,36 @@ class Activity(DB.Model):
|
|
132
157
|
|
133
158
|
@property
|
134
159
|
def average_speed_moving_kmh(self) -> Optional[float]:
|
135
|
-
if self.moving_time:
|
160
|
+
if self.distance_km and self.moving_time:
|
136
161
|
return self.distance_km / (self.moving_time.total_seconds() / 3_600)
|
137
162
|
else:
|
138
163
|
return None
|
139
164
|
|
140
165
|
@property
|
141
166
|
def average_speed_elapsed_kmh(self) -> Optional[float]:
|
142
|
-
if self.elapsed_time:
|
167
|
+
if self.distance_km and self.elapsed_time:
|
143
168
|
return self.distance_km / (self.elapsed_time.total_seconds() / 3_600)
|
144
169
|
else:
|
145
170
|
return None
|
146
171
|
|
172
|
+
@property
|
173
|
+
def time_series_path(self) -> pathlib.Path:
|
174
|
+
return TIME_SERIES_DIR() / f"{self.time_series_uuid}.parquet"
|
175
|
+
|
147
176
|
@property
|
148
177
|
def raw_time_series(self) -> pd.DataFrame:
|
149
|
-
path = TIME_SERIES_DIR() / f"{self.id}.parquet"
|
150
178
|
try:
|
151
|
-
time_series = pd.read_parquet(
|
179
|
+
time_series = pd.read_parquet(self.time_series_path)
|
152
180
|
if "altitude" in time_series.columns:
|
153
181
|
time_series.rename(columns={"altitude": "elevation"}, inplace=True)
|
154
182
|
return time_series
|
155
183
|
except OSError as e:
|
156
|
-
logger.error(f"Error while reading {
|
184
|
+
logger.error(f"Error while reading {self.time_series_path}.")
|
157
185
|
raise
|
158
186
|
|
187
|
+
def replace_time_series(self, time_series: pd.DataFrame) -> None:
|
188
|
+
time_series.to_parquet(self.time_series_path)
|
189
|
+
|
159
190
|
@property
|
160
191
|
def time_series(self) -> pd.DataFrame:
|
161
192
|
if self.index_begin or self.index_end:
|
@@ -165,6 +196,23 @@ class Activity(DB.Model):
|
|
165
196
|
else:
|
166
197
|
return self.raw_time_series
|
167
198
|
|
199
|
+
@property
|
200
|
+
def emoji_string(self) -> str:
|
201
|
+
bits = []
|
202
|
+
if self.kind:
|
203
|
+
bits.append(f"{self.kind.name} with")
|
204
|
+
if self.distance_km:
|
205
|
+
bits.append(f"📏 {round(self.distance_km, 1)} km")
|
206
|
+
if self.elapsed_time:
|
207
|
+
bits.append(f"⏱️ {format_timedelta(self.elapsed_time)} h")
|
208
|
+
if self.elevation_gain:
|
209
|
+
bits.append(f"⛰️ {round(self.elevation_gain, 1)} m")
|
210
|
+
if self.calories:
|
211
|
+
bits.append(f"🍭 {self.calories} kcal")
|
212
|
+
if self.steps:
|
213
|
+
bits.append(f"👣 {self.steps}")
|
214
|
+
return " ".join(bits)
|
215
|
+
|
168
216
|
def delete_data(self) -> None:
|
169
217
|
for path in [
|
170
218
|
TIME_SERIES_DIR() / f"{self.id}.parquet",
|
@@ -173,6 +221,15 @@ class Activity(DB.Model):
|
|
173
221
|
]:
|
174
222
|
path.unlink(missing_ok=True)
|
175
223
|
|
224
|
+
@property
|
225
|
+
def start_local_tz(self) -> Optional[datetime.datetime]:
|
226
|
+
if self.start and self.iana_timezone:
|
227
|
+
return self.start.replace(
|
228
|
+
microsecond=0, tzinfo=zoneinfo.ZoneInfo("UTC")
|
229
|
+
).astimezone(zoneinfo.ZoneInfo(self.iana_timezone))
|
230
|
+
else:
|
231
|
+
return self.start
|
232
|
+
|
176
233
|
|
177
234
|
class Tag(DB.Model):
|
178
235
|
__tablename__ = "tags"
|
@@ -229,14 +286,15 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
229
286
|
.order_by(Activity.start)
|
230
287
|
).all()
|
231
288
|
df = pd.DataFrame(rows)
|
232
|
-
# If the search yields only activities without time information, the dtype isn't derived correctly.
|
233
|
-
df["start"] = pd.to_datetime(df["start"])
|
234
|
-
# start = df["start"].to_list()
|
235
|
-
# random.shuffle(start)
|
236
|
-
# df["start"] = pd.Series(start)
|
237
|
-
df["elapsed_time"] = pd.to_timedelta(df["elapsed_time"])
|
238
289
|
|
239
290
|
if len(df):
|
291
|
+
# If the search yields only activities without time information, the dtype isn't derived correctly.
|
292
|
+
df["start"] = pd.to_datetime(df["start"])
|
293
|
+
# start = df["start"].to_list()
|
294
|
+
# random.shuffle(start)
|
295
|
+
# df["start"] = pd.Series(start)
|
296
|
+
df["elapsed_time"] = pd.to_timedelta(df["elapsed_time"])
|
297
|
+
|
240
298
|
for old, new in [
|
241
299
|
("elapsed_time", "average_speed_elapsed_kmh"),
|
242
300
|
("moving_time", "average_speed_moving_kmh"),
|
@@ -300,7 +358,6 @@ def get_or_make_equipment(name: str, config: Config) -> Equipment:
|
|
300
358
|
equipment = Equipment(
|
301
359
|
name=name, offset_km=config.equipment_offsets.get(name, 0)
|
302
360
|
)
|
303
|
-
DB.session.add(equipment)
|
304
361
|
return equipment
|
305
362
|
|
306
363
|
|
@@ -327,7 +384,7 @@ class Kind(DB.Model):
|
|
327
384
|
__table_args__ = (sa.UniqueConstraint("name", name="kinds_name"),)
|
328
385
|
|
329
386
|
|
330
|
-
def get_or_make_kind(name: str
|
387
|
+
def get_or_make_kind(name: str) -> Kind:
|
331
388
|
kinds = DB.session.scalars(sqlalchemy.select(Kind).where(Kind.name == name)).all()
|
332
389
|
if kinds:
|
333
390
|
assert len(kinds) == 1, f"There must be only one kind with name '{name}'."
|
@@ -335,9 +392,8 @@ def get_or_make_kind(name: str, config: Config) -> Kind:
|
|
335
392
|
else:
|
336
393
|
kind = Kind(
|
337
394
|
name=name,
|
338
|
-
consider_for_achievements=
|
395
|
+
consider_for_achievements=True,
|
339
396
|
)
|
340
|
-
DB.session.add(kind)
|
341
397
|
return kind
|
342
398
|
|
343
399
|
|