Metadata-Version: 2.4
Name: hsl-kaupunkipyora-exporter
Version: 0.1.2
Summary: Parse HSL City Bike ride history and export rides as GPX or TCX files for Strava
Keywords: citybike,cycling,fitness,gpx,helsinki,hsl,kaupunkipyora,strava,tcx
Author: Niko Savola
License-Expression: Apache-2.0
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Utilities
Requires-Dist: beautifulsoup4>=4.13
Requires-Dist: gpxpy>=1.6
Requires-Dist: haversine>=2.9.0
Requires-Dist: polyline>=2.0.4
Requires-Dist: tzdata>=2024.1
Requires-Python: >=3.13
Project-URL: Changelog, https://github.com/nikosavola/hsl-kaupunkipyora-exporter/releases
Project-URL: Issues, https://github.com/nikosavola/hsl-kaupunkipyora-exporter/issues
Project-URL: Repository, https://github.com/nikosavola/hsl-kaupunkipyora-exporter
Description-Content-Type: text/markdown

# HSL Kaupunkipyörä Exporter

[![en](https://img.shields.io/badge/lang-en-red.svg)](./README.md)
[![fi](https://img.shields.io/badge/lang-fi-blue.svg)](./README.fi.md)
[![sv](https://img.shields.io/badge/lang-sv-yellow.svg)](./README.sv.md)

Parse your [HSL City Bike](https://www.hsl.fi/en/my-information/citybikes/ride-history) ride history and export each
ride as a Strava-compatible TCX or GPX file.

## Installation

Requires Python 3.13+. The easiest way to run the tool is via [`uvx`](https://docs.astral.sh/uv/):

```bash
uvx hsl-kaupunkipyora-exporter rides.txt
```

Or install with `pip`:

```bash
pip install hsl-kaupunkipyora-exporter
hsl-kaupunkipyora-exporter rides.txt
```

## Web App

A browser-based version is available at the
[GitHub Pages site](https://nikosavola.github.io/hsl-kaupunkipyora-exporter/). Upload your ride history HTML file or
paste the text, pick your options, and download the resulting files — no installation required. The web app runs
entirely in your browser using [Pyodide](https://pyodide.org).

The browser build reuses the same Python modules as the CLI — it installs the project wheel into Pyodide and calls the
shared `RideHistoryParser` and writers from a thin adapter. Run it locally with:

```bash
just serve-web  # builds the wheel and serves http://localhost:8000/
```

## AI Agent Skill

This repo ships a [skill](skills/hsl-bike-export/SKILL.md) that lets AI Agents like Claude Code run the exporter from
natural language, mapping requests like "export my HSL rides to GPX" to the right CLI flags, and offering to fetch the
ride-history page itself via a connected browser tool (e.g. Claude in Chrome) when you agree to it. The instructions
reference Claude Code's own tools (`ToolSearch`, `Bash`, `Write`), so treat it as Claude-Code-specific for now even
though it's installed via [`skills`](https://github.com/vercel-labs/skills), which also supports other agents. `skills/`
in this repo is the source of truth; installing copies it into `.claude/skills/` in your own project. Install it into
your project with for example:

```bash
npx skills add nikosavola/hsl-kaupunkipyora-exporter
```

## Usage

1. Open your ride history at <https://www.hsl.fi/en/my-information/citybikes/ride-history>.
1. Save the page as HTML (`Ctrl+S`) **or** copy-paste the visible text into a `.txt` file.
1. Run the exporter:

```bash
uvx hsl-kaupunkipyora-exporter rides.html
```

### Path Modes

The exporter supports three distinct modes for handling geographic data:

1. **Summary Only (Default)**: Exports a TCX file containing the exact distance and duration reported by HSL, but no GPS
   trackpoints. This is the most accurate way to record kilometers in Strava without guessing the path.
1. **Linear Path (`--linear`)**: Includes a simple two-point straight line between the departure and return stations.
   Useful if you want a basic map visualization.
1. **Routed Path (`--use-route`)**: Fetches the suggested cycling route from the
   [Digitransit API](https://digitransit.fi/en/developers/apis/). This provides a realistic path on the map and
   preserves HSL distance data (when using TCX). Requires a
   [free API key](https://digitransit.fi/en/developers/api-registration/).

### Options

| Flag                    | Description                                                             |
| ----------------------- | ----------------------------------------------------------------------- |
| `--output-dir DIR`      | Directory to write files into (default: `./tcx_output`)                 |
| `--format FMT`          | Export format: `tcx` (default) or `gpx`.                                |
| `--linear`              | Include a straight-line path between stations                           |
| `--use-route`           | Use suggested HSL cycling route instead of a straight line              |
| `--api-key KEY`         | Digitransit API key (alternative to `DIGITRANSIT_API_KEY` env var)      |
| `--refresh-stations`    | Force re-download of the bike station coordinate list                   |
| `--cache-ttl-days DAYS` | Refresh station cache after this many days (default: 30, env var below) |
| `-n`, `--dry-run`       | Preview which files would be written or skipped without writing         |
| `--zip`                 | Bundle all exported files into a single `rides.zip` archive             |
| `--merge`               | Write one file with all rides (multi-track GPX / multi-activity TCX)    |
| `-v`, `--verbose`       | Enable verbose/debug logging                                            |

The station cache TTL can also be set via the `HSL_KAUPUNKIPYORA_CACHE_TTL_DAYS` environment variable.

### TCX vs GPX

While GPX is the most common format, it does not support an explicit "total distance" override. Strava calculates
distance based on the GPS points provided.

**TCX** is the default and recommended format because it allows the tool to tell Strava exactly how many kilometers the
ride was, regardless of the GPS path.

```bash
# Export as TCX with a straight line between stations
uvx hsl-kaupunkipyora-exporter rides.txt --linear
```

### Routed Path Setup

To use the actual cycling route suggested by HSL, you need a Digitransit API key:

1. Register for a free key at [Digitransit Developer Portal](https://digitransit.fi/en/developers/api-registration/).
1. Provide the key via the `--api-key` flag or the `DIGITRANSIT_API_KEY` environment variable.

```bash
uvx hsl-kaupunkipyora-exporter rides.txt --use-route --api-key your_key_here
```

### Kilometrikisa

This is a convenient way to add your **Alepa Fillari** kilometers to [Kilometrikisa](https://www.kilometrikisa.fi/) by
importing your rides into Strava first.

## How it Works

```mermaid
graph TD
    classDef input fill:#4A90D9,stroke:#2171B5,color:#fff
    classDef parser fill:#E67E22,stroke:#CA6F1E,color:#fff
    classDef lookup fill:#8E44AD,stroke:#7D3C98,color:#fff
    classDef decision fill:#FDEBD0,stroke:#E67E22,color:#000
    classDef skip fill:#E74C3C,stroke:#CB4335,color:#fff
    classDef pathNode fill:#A9DFBF,stroke:#27AE60,color:#000
    classDef api fill:#76D7C4,stroke:#16A085,color:#000
    classDef writer fill:#5DADE2,stroke:#2980B9,color:#fff
    classDef output fill:#2ECC71,stroke:#27AE60,color:#000

    A[HSL Ride History<br/>HTML or Text]:::input --> B(RideHistoryParser<br/>Parses HTML & plain-text<br/>ride history files):::parser
    B --> C{StationLookup<br/>Resolves station names<br/>to GPS coordinates}:::lookup
    C -- Coordinates Found --> D{Path Mode?}:::decision
    C -- Not Found --> E[Skip Ride]:::skip

    D -- Default --> F[Summary Only<br/>Exact HSL distance &<br/>duration, no GPS points]:::pathNode
    D -- "--linear" --> G[Linear Path<br/>Straight line between<br/>departure & return stations]:::pathNode
    D -- "--use-route" --> H[fetch_route<br/>Fetches cycling route<br/>via Digitransit GraphQL API]:::api

    F --> I(TCX/GPX Writer<br/>Serialises rides into<br/>Strava-compatible files):::writer
    G --> I
    H --> I

    I --> J[Strava-compatible<br/>TCX or GPX files]:::output
```

## Development

Use [`just`](https://github.com/casey/just) to run tasks.

```bash
git clone https://github.com/nikosavola/hsl-kaupunkipyora-exporter.git
cd hsl-kaupunkipyora-exporter
just install
just test
```
