geo-activity-playground 0.44.0__tar.gz → 1.0.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-0.44.0 → geo_activity_playground-1.0.0}/PKG-INFO +2 -1
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/config.py +1 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/datamodel.py +6 -0
- geo_activity_playground-1.0.0/geo_activity_playground/core/export.py +129 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/meta_search.py +2 -2
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/directory.py +3 -2
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/strava_checkout.py +2 -1
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/app.py +3 -1
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/authenticator.py +4 -2
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/auth_blueprint.py +3 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/eddington_blueprints.py +17 -8
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/entry_views.py +5 -3
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/equipment_blueprint.py +1 -1
- geo_activity_playground-1.0.0/geo_activity_playground/webui/blueprints/explorer_blueprint.py +534 -0
- geo_activity_playground-1.0.0/geo_activity_playground/webui/blueprints/export_blueprint.py +30 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/settings_blueprint.py +64 -1
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/upload_blueprint.py +16 -3
- geo_activity_playground-1.0.0/geo_activity_playground/webui/static/server-side-explorer.js +55 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/auth/index.html.j2 +1 -0
- geo_activity_playground-1.0.0/geo_activity_playground/webui/templates/explorer/server-side.html.j2 +77 -0
- geo_activity_playground-1.0.0/geo_activity_playground/webui/templates/export/index.html.j2 +39 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/home.html.j2 +2 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/page.html.j2 +3 -6
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/summary/index.html.j2 +2 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/pyproject.toml +2 -1
- geo_activity_playground-0.44.0/geo_activity_playground/webui/blueprints/explorer_blueprint.py +0 -422
- geo_activity_playground-0.44.0/geo_activity_playground/webui/templates/explorer/index.html.j2 +0 -148
- geo_activity_playground-0.44.0/geo_activity_playground/webui/templates/explorer/server-side.html.j2 +0 -72
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/LICENSE +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/__main__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/README +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/env.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/script.py.mako +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/0f02b92c4f94_add_tag_color.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/93cc82ad1b60_add_parametricplotspec.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/da2cba03b71d_add_photos.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/alembic/versions/script.py.mako +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/activities.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/coordinates.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/enrichment.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/heart_rate.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/missing_values.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/parametric_plot.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/paths.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/privacy_zones.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/raster_map.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/similarity.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/summary_stats.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/tasks.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_datamodel.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_meta_search.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_missing_values.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_summary_stats.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_tiles.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/test_time_conversion.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/tiles.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/core/time_conversion.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/explorer/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/explorer/grid_file.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/explorer/tile_visits.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/explorer/video.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/heatmap_video.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/activity_parsers.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/csv_parser.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/strava_api.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/test_csv_parser.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/test_directory.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/importers/test_strava_api.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/__init__.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/activity_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/calendar_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/heatmap_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/photo_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/search_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/square_planner_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/summary_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/blueprints/tile_blueprint.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/columns.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/flasher.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/plot_util.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/search_util.py +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/Leaflet.fullscreen.min.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/MarkerCluster.Default.css +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/MarkerCluster.css +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/android-chrome-192x192.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/android-chrome-512x512.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/apple-touch-icon.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/bootstrap-dark-mode.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/bootstrap.bundle.min.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/bootstrap.min.css +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/browserconfig.xml +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/favicon-16x16.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/favicon-32x32.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/favicon-48x48.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/favicon.ico +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/favicon.svg +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/fullscreen.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/fullscreen@2x.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/images/layers-2x.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/images/layers.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/images/marker-icon.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/leaflet.css +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/leaflet.fullscreen.css +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/leaflet.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/leaflet.markercluster.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/mstile-150x150.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/site.webmanifest +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/table-sort.min.js +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/vega-embed@6 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/vega-lite@4 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/vega@5 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/web-app-manifest-192x192.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/static/web-app-manifest-512x512.png +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/day.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/edit.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/lines.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/name.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/show.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/activity/trim.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/calendar/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/calendar/month.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/eddington/distance.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/equipment/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/heatmap/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/photo/map.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/photo/new.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/plot_builder/edit.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/plot_builder/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/search/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/search_form.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/admin-password.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/color-schemes.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/heart-rate.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/metadata-extraction.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/privacy-zones.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/segmentation.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/sharepic.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/strava.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/tags-edit.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/tags-list.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/settings/tags-new.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/square_planner/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/upload/index.html.j2 +0 -0
- {geo_activity_playground-0.44.0 → geo_activity_playground-1.0.0}/geo_activity_playground/webui/templates/upload/reload.html.j2 +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: geo-activity-playground
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
4
4
|
Summary: Analysis of geo data activities like rides, runs or hikes.
|
5
5
|
License: MIT
|
6
6
|
Author: Martin Ueding
|
@@ -28,6 +28,7 @@ Requires-Dist: gpxpy (>=1.5.0,<2.0.0)
|
|
28
28
|
Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
|
29
29
|
Requires-Dist: matplotlib (>=3.10.1,<4.0.0)
|
30
30
|
Requires-Dist: numpy (>=2.2.3,<3.0.0)
|
31
|
+
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
31
32
|
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
32
33
|
Requires-Dist: pyarrow (>=19.0.1,<20.0.0)
|
33
34
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
@@ -38,6 +38,7 @@ class Config:
|
|
38
38
|
privacy_zones: dict[str, list[list[float]]] = dataclasses.field(
|
39
39
|
default_factory=dict
|
40
40
|
)
|
41
|
+
reliable_elevation_measurements: bool = True
|
41
42
|
sharepic_suppressed_fields: list[str] = dataclasses.field(default_factory=list)
|
42
43
|
strava_client_id: int = 131693
|
43
44
|
strava_client_secret: str = "0ccc0100a2c218512a7ef0cea3b0e322fb4b4365"
|
@@ -29,6 +29,9 @@ from .paths import TIME_SERIES_DIR
|
|
29
29
|
logger = logging.getLogger(__name__)
|
30
30
|
|
31
31
|
|
32
|
+
DEFAULT_UNKNOWN_NAME = "Unknown"
|
33
|
+
|
34
|
+
|
32
35
|
class ActivityMeta(TypedDict):
|
33
36
|
average_speed_elapsed_kmh: float
|
34
37
|
average_speed_moving_kmh: float
|
@@ -226,6 +229,9 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
226
229
|
.order_by(Activity.start)
|
227
230
|
).all()
|
228
231
|
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
|
+
df["elapsed_time"] = pd.to_timedelta(df["elapsed_time"])
|
229
235
|
|
230
236
|
if len(df):
|
231
237
|
for old, new in [
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import io
|
2
|
+
import zipfile
|
3
|
+
from typing import IO
|
4
|
+
|
5
|
+
import geojson
|
6
|
+
import gpxpy.gpx
|
7
|
+
import pandas as pd
|
8
|
+
import sqlalchemy
|
9
|
+
from tqdm import tqdm
|
10
|
+
|
11
|
+
from .datamodel import Activity
|
12
|
+
from .datamodel import DB
|
13
|
+
from .datamodel import query_activity_meta
|
14
|
+
|
15
|
+
|
16
|
+
def export_all(meta_format: str, activity_format: str) -> bytes:
|
17
|
+
meta = query_activity_meta()
|
18
|
+
buffer = io.BytesIO()
|
19
|
+
with zipfile.ZipFile(buffer, "x") as zf:
|
20
|
+
with zf.open(f"activities.{meta_format}", mode="w") as f:
|
21
|
+
match meta_format:
|
22
|
+
case "csv":
|
23
|
+
export_meta_as_csv(meta, f)
|
24
|
+
case "json":
|
25
|
+
export_meta_as_json(meta, f)
|
26
|
+
case "ods":
|
27
|
+
export_meta_as_xlsx(meta, f)
|
28
|
+
case "parquet":
|
29
|
+
export_meta_as_parquet(meta, f)
|
30
|
+
case "xlsx":
|
31
|
+
export_meta_as_xlsx(meta, f)
|
32
|
+
case _:
|
33
|
+
raise ValueError(
|
34
|
+
f"Format {meta_format} is not supported for metadata."
|
35
|
+
)
|
36
|
+
if activity_format:
|
37
|
+
zf.mkdir("activities")
|
38
|
+
for activity in tqdm(
|
39
|
+
DB.session.scalars(sqlalchemy.select(Activity)).all(),
|
40
|
+
desc="Export activity time series",
|
41
|
+
):
|
42
|
+
with zf.open(
|
43
|
+
f"activities/{activity.id}.{activity_format}", mode="w"
|
44
|
+
) as f:
|
45
|
+
match activity_format:
|
46
|
+
case "csv":
|
47
|
+
export_activity_as_csv(activity, f)
|
48
|
+
case "geojson":
|
49
|
+
export_activity_as_geojson(activity, f)
|
50
|
+
case "gpx":
|
51
|
+
export_activity_as_gpx(activity, f)
|
52
|
+
case "ods":
|
53
|
+
export_activity_as_xlsx(activity, f)
|
54
|
+
case "parquet":
|
55
|
+
export_activity_as_parquet(activity, f)
|
56
|
+
case "xlsx":
|
57
|
+
export_activity_as_xlsx(activity, f)
|
58
|
+
case _:
|
59
|
+
raise ValueError(
|
60
|
+
f"Format {activity_format} is not supported for activity time series."
|
61
|
+
)
|
62
|
+
return bytes(buffer.getbuffer())
|
63
|
+
|
64
|
+
|
65
|
+
def export_meta_as_csv(meta: pd.DataFrame, target: IO[bytes]) -> None:
|
66
|
+
meta.to_csv(target, index=False)
|
67
|
+
|
68
|
+
|
69
|
+
def export_meta_as_json(meta: pd.DataFrame, target: IO[bytes]) -> None:
|
70
|
+
buffer = io.StringIO()
|
71
|
+
meta.to_json(buffer, index=False)
|
72
|
+
target.write(buffer.getvalue().encode())
|
73
|
+
|
74
|
+
|
75
|
+
def export_meta_as_parquet(meta: pd.DataFrame, target: IO[bytes]) -> None:
|
76
|
+
meta.to_parquet(target, index=False)
|
77
|
+
|
78
|
+
|
79
|
+
def export_meta_as_xlsx(meta: pd.DataFrame, target: IO[bytes]) -> None:
|
80
|
+
meta.to_excel(target, index=False)
|
81
|
+
|
82
|
+
|
83
|
+
def export_activity_as_csv(activity: Activity, target: IO[bytes]) -> None:
|
84
|
+
activity.time_series.to_csv(target, index=False)
|
85
|
+
|
86
|
+
|
87
|
+
def export_activity_as_geojson(activity: Activity, target: IO[bytes]) -> None:
|
88
|
+
ts = activity.time_series
|
89
|
+
result = geojson.MultiLineString(
|
90
|
+
coordinates=[
|
91
|
+
[(lon, lat) for lat, lon in zip(group["latitude"], group["longitude"])]
|
92
|
+
for segment_id, group in ts.groupby("segment_id")
|
93
|
+
]
|
94
|
+
)
|
95
|
+
buffer = io.StringIO()
|
96
|
+
geojson.dump(result, buffer)
|
97
|
+
target.write(buffer.getvalue().encode())
|
98
|
+
|
99
|
+
|
100
|
+
def export_activity_as_gpx(activity: Activity, target: IO[bytes]) -> None:
|
101
|
+
g = gpxpy.gpx.GPX()
|
102
|
+
|
103
|
+
gpx_track = gpxpy.gpx.GPXTrack()
|
104
|
+
g.tracks.append(gpx_track)
|
105
|
+
|
106
|
+
ts = activity.time_series
|
107
|
+
for segment_id, group in ts.groupby("segment_id"):
|
108
|
+
gpx_segment = gpxpy.gpx.GPXTrackSegment()
|
109
|
+
gpx_track.segments.append(gpx_segment)
|
110
|
+
|
111
|
+
for index, row in group.iterrows():
|
112
|
+
gpx_segment.points.append(
|
113
|
+
gpxpy.gpx.GPXTrackPoint(
|
114
|
+
row["latitude"],
|
115
|
+
row["longitude"],
|
116
|
+
elevation=row.get("elevation", None),
|
117
|
+
time=row.get("time", None),
|
118
|
+
)
|
119
|
+
)
|
120
|
+
|
121
|
+
target.write(g.to_xml().encode())
|
122
|
+
|
123
|
+
|
124
|
+
def export_activity_as_parquet(activity: Activity, target: IO[bytes]) -> None:
|
125
|
+
activity.time_series.to_parquet(target, index=False)
|
126
|
+
|
127
|
+
|
128
|
+
def export_activity_as_xlsx(activity: Activity, target: IO[bytes]) -> None:
|
129
|
+
activity.time_series.to_excel(target, index=False)
|
@@ -120,7 +120,7 @@ class SearchQuery:
|
|
120
120
|
variables.append(("distance_km_max", self.distance_km_max))
|
121
121
|
|
122
122
|
return "&".join(
|
123
|
-
f"{key}={urllib.parse.quote_plus(value)}" for key, value in variables
|
123
|
+
f"{key}={urllib.parse.quote_plus(str(value))}" for key, value in variables
|
124
124
|
)
|
125
125
|
|
126
126
|
|
@@ -158,7 +158,7 @@ def apply_search_query(
|
|
158
158
|
)
|
159
159
|
|
160
160
|
if search_query.start_begin:
|
161
|
-
filter_clauses.append(Activity.start
|
161
|
+
filter_clauses.append(Activity.start >= search_query.start_begin)
|
162
162
|
if search_query.start_end:
|
163
163
|
filter_clauses.append(Activity.start < search_query.start_end)
|
164
164
|
|
@@ -10,6 +10,7 @@ from tqdm import tqdm
|
|
10
10
|
|
11
11
|
from ..core.config import Config
|
12
12
|
from ..core.datamodel import ActivityMeta
|
13
|
+
from ..core.datamodel import DEFAULT_UNKNOWN_NAME
|
13
14
|
from ..core.paths import activity_extracted_dir
|
14
15
|
from ..core.paths import activity_extracted_meta_dir
|
15
16
|
from ..core.paths import activity_extracted_time_series_dir
|
@@ -84,8 +85,8 @@ def import_from_directory(
|
|
84
85
|
# https://stackoverflow.com/a/74718395/653152
|
85
86
|
name=path.name.removesuffix("".join(path.suffixes)),
|
86
87
|
path=str(path),
|
87
|
-
kind=
|
88
|
-
equipment=
|
88
|
+
kind=DEFAULT_UNKNOWN_NAME,
|
89
|
+
equipment=DEFAULT_UNKNOWN_NAME,
|
89
90
|
consider_for_achievements=True,
|
90
91
|
)
|
91
92
|
activity_meta.update(activity_meta_from_file)
|
@@ -13,6 +13,7 @@ import pandas as pd
|
|
13
13
|
from tqdm import tqdm
|
14
14
|
|
15
15
|
from ..core.datamodel import ActivityMeta
|
16
|
+
from ..core.datamodel import DEFAULT_UNKNOWN_NAME
|
16
17
|
from ..core.paths import activity_extracted_meta_dir
|
17
18
|
from ..core.paths import activity_extracted_time_series_dir
|
18
19
|
from ..core.paths import strava_last_activity_date_path
|
@@ -277,7 +278,7 @@ def convert_strava_checkout(
|
|
277
278
|
nan_as_none(row["Activity Gear"])
|
278
279
|
or nan_as_none(row["Bike"])
|
279
280
|
or nan_as_none(row["Gear"])
|
280
|
-
or
|
281
|
+
or DEFAULT_UNKNOWN_NAME
|
281
282
|
)
|
282
283
|
activity_file = checkout_path / row["Filename"]
|
283
284
|
|
@@ -38,6 +38,7 @@ from .blueprints.eddington_blueprints import register_eddington_blueprint
|
|
38
38
|
from .blueprints.entry_views import register_entry_views
|
39
39
|
from .blueprints.equipment_blueprint import make_equipment_blueprint
|
40
40
|
from .blueprints.explorer_blueprint import make_explorer_blueprint
|
41
|
+
from .blueprints.export_blueprint import make_export_blueprint
|
41
42
|
from .blueprints.heatmap_blueprint import make_heatmap_blueprint
|
42
43
|
from .blueprints.photo_blueprint import make_photo_blueprint
|
43
44
|
from .blueprints.plot_builder_blueprint import make_plot_builder_blueprint
|
@@ -160,6 +161,7 @@ def web_ui_main(
|
|
160
161
|
tile_getter,
|
161
162
|
image_transforms,
|
162
163
|
),
|
164
|
+
"/export": make_export_blueprint(authenticator),
|
163
165
|
"/heatmap": make_heatmap_blueprint(
|
164
166
|
repository, tile_visit_accessor, config_accessor(), search_query_history
|
165
167
|
),
|
@@ -175,7 +177,7 @@ def web_ui_main(
|
|
175
177
|
"/summary": make_summary_blueprint(repository, config, search_query_history),
|
176
178
|
"/tile": make_tile_blueprint(image_transforms, tile_getter),
|
177
179
|
"/upload": make_upload_blueprint(
|
178
|
-
repository, tile_visit_accessor, config_accessor(), authenticator
|
180
|
+
repository, tile_visit_accessor, config_accessor(), authenticator, flasher
|
179
181
|
),
|
180
182
|
}
|
181
183
|
|
@@ -3,8 +3,10 @@ from typing import Callable
|
|
3
3
|
|
4
4
|
from flask import flash
|
5
5
|
from flask import redirect
|
6
|
+
from flask import request
|
6
7
|
from flask import session
|
7
8
|
from flask import url_for
|
9
|
+
from flask.typing import RouteCallable
|
8
10
|
|
9
11
|
from ..core.config import Config
|
10
12
|
|
@@ -32,14 +34,14 @@ class Authenticator:
|
|
32
34
|
|
33
35
|
|
34
36
|
def needs_authentication(authenticator: Authenticator) -> Callable:
|
35
|
-
def decorator(route:
|
37
|
+
def decorator(route: RouteCallable) -> RouteCallable:
|
36
38
|
@functools.wraps(route)
|
37
39
|
def wrapped_route(*args, **kwargs):
|
38
40
|
if authenticator.is_authenticated():
|
39
41
|
return route(*args, **kwargs)
|
40
42
|
else:
|
41
43
|
flash("You need to be logged in to view that site.", category="Warning")
|
42
|
-
return redirect(url_for("auth.index"))
|
44
|
+
return redirect(url_for("auth.index", redirect=request.url))
|
43
45
|
|
44
46
|
return wrapped_route
|
45
47
|
|
@@ -14,9 +14,12 @@ def make_auth_blueprint(authenticator: Authenticator) -> Blueprint:
|
|
14
14
|
def index():
|
15
15
|
if request.method == "POST":
|
16
16
|
authenticator.authenticate(request.form["password"])
|
17
|
+
if redirect_to := request.form["redirect"]:
|
18
|
+
return redirect(redirect_to)
|
17
19
|
return render_template(
|
18
20
|
"auth/index.html.j2",
|
19
21
|
is_authenticated=authenticator.is_authenticated(),
|
22
|
+
redirect=request.args.get("redirect", ""),
|
20
23
|
)
|
21
24
|
|
22
25
|
@blueprint.route("/logout")
|
@@ -26,7 +26,12 @@ def register_eddington_blueprint(
|
|
26
26
|
@blueprint.route("/")
|
27
27
|
def distance():
|
28
28
|
return _render_eddington_template(
|
29
|
-
repository,
|
29
|
+
repository,
|
30
|
+
request,
|
31
|
+
search_query_history,
|
32
|
+
"distance",
|
33
|
+
column_distance,
|
34
|
+
[1],
|
30
35
|
)
|
31
36
|
|
32
37
|
@blueprint.route("/elevation_gain")
|
@@ -64,6 +69,10 @@ def _render_eddington_template(
|
|
64
69
|
.copy()
|
65
70
|
)
|
66
71
|
|
72
|
+
assert (
|
73
|
+
len(activities) > 0
|
74
|
+
), "The filter has selected zero elements, that cannot work here."
|
75
|
+
|
67
76
|
activities["year"] = [start.year for start in activities["start"]]
|
68
77
|
activities["date"] = [start.date() for start in activities["start"]]
|
69
78
|
activities["isoyear"] = [start.isocalendar().year for start in activities["start"]]
|
@@ -111,24 +120,24 @@ def _render_eddington_template(
|
|
111
120
|
)
|
112
121
|
|
113
122
|
|
114
|
-
def _get_values_per_group(grouped,
|
123
|
+
def _get_values_per_group(grouped, column_name, divisor) -> tuple[int, pd.DataFrame]:
|
115
124
|
sum_per_group = grouped.apply(
|
116
|
-
lambda group: int(sum(group[
|
125
|
+
lambda group: int(sum(group[column_name])), include_groups=False
|
117
126
|
)
|
118
127
|
counts = dict(zip(*np.unique(sorted(sum_per_group), return_counts=True)))
|
119
128
|
eddington = pd.DataFrame(
|
120
|
-
{
|
129
|
+
{column_name: d, "count": counts.get(d, 0)}
|
121
130
|
for d in range(max(counts.keys()) + 1)
|
122
131
|
)
|
123
132
|
eddington["total"] = eddington["count"][::-1].cumsum()[::-1]
|
124
|
-
eddington[f"{
|
133
|
+
eddington[f"{column_name}_div"] = eddington[column_name] // divisor
|
125
134
|
en = (
|
126
|
-
eddington.loc[eddington["total"] >= eddington[f"{
|
127
|
-
"
|
135
|
+
eddington.loc[eddington["total"] >= eddington[f"{column_name}_div"]][
|
136
|
+
f"{column_name}_div"
|
128
137
|
].iloc[-1]
|
129
138
|
* divisor
|
130
139
|
)
|
131
|
-
eddington["missing"] = eddington[f"{
|
140
|
+
eddington["missing"] = eddington[f"{column_name}_div"] - eddington["total"]
|
132
141
|
|
133
142
|
return en, eddington
|
134
143
|
|
@@ -31,9 +31,11 @@ def register_entry_views(
|
|
31
31
|
context["distance_last_30_days_plot"] = _last_30_days_meta_plot(
|
32
32
|
repository.meta, kind_scale, column_distance
|
33
33
|
)
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
|
35
|
+
if config.reliable_elevation_measurements:
|
36
|
+
context["elevation_gain_last_30_days_plot"] = _last_30_days_meta_plot(
|
37
|
+
repository.meta, kind_scale, column_elevation_gain
|
38
|
+
)
|
37
39
|
|
38
40
|
context["latest_activities"] = collections.defaultdict(list)
|
39
41
|
for activity in DB.session.scalars(
|
@@ -21,7 +21,7 @@ def make_equipment_blueprint(
|
|
21
21
|
)
|
22
22
|
|
23
23
|
# Prepare data for the stacked area chart
|
24
|
-
activities = repository.meta
|
24
|
+
activities = repository.meta.dropna(subset=["start"])
|
25
25
|
activities["month"] = (
|
26
26
|
activities["start"].dt.to_period("M").apply(lambda r: r.start_time)
|
27
27
|
)
|