From 8c1ad7ebdf20220d0f70b193c2a979f9b8e03518 Mon Sep 17 00:00:00 2001 From: "friedemann.blume" Date: Sun, 21 Jul 2024 14:10:43 +0200 Subject: [PATCH] init - v1 --- Dockerfile | 38 ++ Readme.md | 82 ++++ app.py | 71 +++ docker-compose.yml | 8 + input/1713548128_activities.fit | Bin 0 -> 18480 bytes input/1718720200_activities.fit | Bin 0 -> 25604 bytes output/1713548128_activities.gpx | 720 +++++++++++++++++++++++++++++ output/1718720200_activities.gpx | 746 +++++++++++++++++++++++++++++++ requirements.txt | 2 + templates/index.html | 133 ++++++ 10 files changed, 1800 insertions(+) create mode 100644 Dockerfile create mode 100644 Readme.md create mode 100644 app.py create mode 100644 docker-compose.yml create mode 100644 input/1713548128_activities.fit create mode 100644 input/1718720200_activities.fit create mode 100644 output/1713548128_activities.gpx create mode 100644 output/1718720200_activities.gpx create mode 100644 requirements.txt create mode 100644 templates/index.html diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..77f818a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM debian:bookworm-slim + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + python3 \ + python3-venv \ + python3-pip \ + gpsbabel \ + && rm -rf /var/lib/apt/lists/* + +# Set up app directory +WORKDIR /app + +# Copy application files +COPY app.py /app/ +COPY templates /app/templates +COPY requirements.txt /app/ + +# Create and activate virtual environment +ENV VIRTUAL_ENV=/opt/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +# Install Python dependencies in virtual environment +RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt + +# Create input and output directories +RUN mkdir /app/input /app/output + +# Set environment variables +ENV FLASK_APP=app.py +ENV FLASK_RUN_HOST=0.0.0.0 + +# Expose port +EXPOSE 5000 + +# Run the application +CMD ["python", "-m", "flask", "run"] diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..9a29d65 --- /dev/null +++ b/Readme.md @@ -0,0 +1,82 @@ +# FIT to GPX Converter + +FIT to GPX Converter is a web application that allows users to easily convert Garmin FIT (Flexible and Interoperable Data Transfer) files to GPX (GPS Exchange Format) files. This tool is particularly useful for athletes, outdoor enthusiasts, and anyone who needs to convert their fitness tracking data from FIT to the more widely compatible GPX format. + +## Features + +- Upload FIT files through a user-friendly web interface +- Automatic conversion of FIT files to GPX format +- View and manage both input (FIT) and output (GPX) files +- Select and delete multiple files +- Responsive design for both desktop and mobile use +- Auto-refresh to show newly converted files + +## Prerequisites + +Before you begin, ensure you have met the following requirements: + +- Docker and Docker Compose installed on your system +- Git for cloning the repository + +## Installation + +To install FIT to GPX Converter, follow these steps: + +1. Clone the repository: + ``` + git clone https://github.com/your-username/fit-to-gpx-converter.git + cd fit-to-gpx-converter + ``` + +2. Build the Docker image: + ``` + docker-compose build + ``` + +3. Start the application: + ``` + docker-compose up + ``` + +The application should now be running and accessible at `http://localhost:5000`. + +## Usage + +1. Open your web browser and navigate to `http://localhost:5000`. +2. Use the file input to select and upload a .fit file. +3. Click the "Upload and Convert" button. +4. Wait for the conversion process to complete. +5. The converted .gpx file will appear in the "Output Files" list. +6. Click on the file name in the "Output Files" list to download the converted .gpx file. + +### Managing Files + +- To delete input or output files, select the checkboxes next to the files you wish to remove, then click the "Delete Selected Files" button for the respective list. +- The page automatically refreshes every 30 seconds to show newly converted files. + +## Contributing + +Contributions to the FIT to GPX Converter are welcome. Please follow these steps to contribute: + +1. Fork the repository. +2. Create a new branch: `git checkout -b `. +3. Make your changes and commit them: `git commit -m ''` +4. Push to the original branch: `git push origin /` +5. Create the pull request. + +Alternatively, see the GitHub documentation on [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). + +## License + +This project uses the following license: [MIT License](https://opensource.org/licenses/MIT). + +## Contact + +If you want to contact the maintainer of this project, please email [your-email@example.com](mailto:your-email@example.com). + +## Acknowledgements + +- [Flask](https://flask.palletsprojects.com/) - The web framework used +- [GPSBabel](https://www.gpsbabel.org/) - Used for file conversion +- [Tailwind CSS](https://tailwindcss.com/) - Used for styling +- [Alpine.js](https://alpinejs.dev/) - Used for interactive elements diff --git a/app.py b/app.py new file mode 100644 index 0000000..cc366c5 --- /dev/null +++ b/app.py @@ -0,0 +1,71 @@ +import os +from flask import Flask, request, render_template, send_from_directory, redirect, url_for, flash, jsonify +import subprocess +from werkzeug.utils import secure_filename + +app = Flask(__name__) +app.secret_key = 'your_secret_key_here' # Required for flash messaging + +INPUT_FOLDER = '/app/input' +OUTPUT_FOLDER = '/app/output' +ALLOWED_EXTENSIONS = {'fit'} + +app.config['INPUT_FOLDER'] = INPUT_FOLDER +app.config['OUTPUT_FOLDER'] = OUTPUT_FOLDER + +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + +@app.route('/', methods=['GET', 'POST']) +def upload_file(): + if request.method == 'POST': + if 'file' not in request.files: + flash('No file part', 'error') + return redirect(url_for('upload_file')) + file = request.files['file'] + if file.filename == '': + flash('No selected file', 'error') + return redirect(url_for('upload_file')) + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + input_path = os.path.join(app.config['INPUT_FOLDER'], filename) + file.save(input_path) + + output_filename = f"{os.path.splitext(filename)[0]}.gpx" + output_path = os.path.join(app.config['OUTPUT_FOLDER'], output_filename) + + subprocess.run(['gpsbabel', '-i', 'garmin_fit', '-f', input_path, '-o', 'gpx', '-F', output_path]) + + flash('File uploaded and converted successfully', 'success') + return redirect(url_for('upload_file')) + else: + flash('Invalid file type. Please upload a .fit file.', 'error') + return redirect(url_for('upload_file')) + + input_files = os.listdir(app.config['INPUT_FOLDER']) + output_files = os.listdir(app.config['OUTPUT_FOLDER']) + return render_template('index.html', input_files=input_files, output_files=output_files) + +@app.route('/download/') +def download_file(filename): + return send_from_directory(app.config['OUTPUT_FOLDER'], filename, as_attachment=True) + +@app.route('/delete', methods=['POST']) +def delete_files(): + files_to_delete = request.json.get('files', []) + folder = request.json.get('folder', '') + + if folder not in ['input', 'output']: + return jsonify({'error': 'Invalid folder specified'}), 400 + + target_folder = app.config['INPUT_FOLDER'] if folder == 'input' else app.config['OUTPUT_FOLDER'] + + for filename in files_to_delete: + file_path = os.path.join(target_folder, filename) + if os.path.exists(file_path): + os.remove(file_path) + + return jsonify({'message': 'Files deleted successfully'}), 200 + +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0') diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cbfff9e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +services: + fit2gpx: + image: fit2gpx + ports: + - "5001:5000" + volumes: + - ./input:/app/input + - ./output:/app/output diff --git a/input/1713548128_activities.fit b/input/1713548128_activities.fit new file mode 100644 index 0000000000000000000000000000000000000000..bd8b713d03b68ef66364cb25b241c7d75eaa8994 GIT binary patch literal 18480 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 SsA1#$T*2PHK^3mP?|%WE+jM#W literal 0 HcmV?d00001 diff --git a/input/1718720200_activities.fit b/input/1718720200_activities.fit new file mode 100644 index 0000000000000000000000000000000000000000..402600bc0905574dfa814b36bf398090bb201dcb GIT binary patch literal 25604 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 + + + + + LAP001 + LAP001 + LAP001 + + + + + 119.800 + + 4.180000 + + + 120.600 + + 5.141000 + + + 121.400 + + 4.637000 + + + 122.000 + + 5.141000 + + + 122.200 + + 4.637000 + + + 123.800 + + 3.938000 + + + 124.200 + + 3.919000 + + + 124.600 + + 3.919000 + + + 124.800 + + 5.160000 + + + 125.000 + + 5.440000 + + + 125.000 + + 3.228000 + + + 125.200 + + 4.731000 + + + 125.200 + + 4.731000 + + + 125.200 + + 4.721000 + + + 125.200 + + 4.385000 + + + 125.600 + + 4.721000 + + + 125.800 + + 4.563000 + + + 126.000 + + 4.339000 + + + 126.000 + + 4.385000 + + + 126.200 + + 4.563000 + + + 126.200 + + 4.563000 + + + 126.200 + + 4.964000 + + + 126.400 + + 4.964000 + + + 126.400 + + 4.964000 + + + 126.600 + + 5.048000 + + + 126.600 + + 5.645000 + + + 126.800 + + 6.457000 + + + 126.000 + + 5.766000 + + + 126.200 + + 5.048000 + + + 126.400 + + 3.891000 + + + 126.600 + + 4.507000 + + + 126.400 + + 5.757000 + + + 126.400 + + 5.113000 + + + 127.600 + + 5.496000 + + + 128.200 + + 5.570000 + + + 128.600 + + 5.141000 + + + 129.000 + + 5.095000 + + + 129.200 + + 4.059000 + + + 129.400 + + 2.118000 + + + 129.400 + + 1.903000 + + + 129.600 + + 0.000000 + + + + + 130.400 + + 2.762000 + + + 130.400 + + 3.256000 + + + 129.800 + + 4.152000 + + + 130.200 + + 5.179000 + + + 131.200 + + 5.272000 + + + 131.800 + + 5.179000 + + + 131.800 + + 5.281000 + + + 131.400 + + 5.552000 + + + 130.800 + + 5.552000 + + + 130.600 + + 5.552000 + + + 129.600 + + 5.636000 + + + 129.400 + + 5.636000 + + + 129.000 + + 5.710000 + + + 129.000 + + 6.466000 + + + 128.600 + + 6.485000 + + + 128.400 + + 6.597000 + + + 128.400 + + 6.541000 + + + 127.400 + + 6.494000 + + + 127.400 + + 6.597000 + + + 127.400 + + 6.597000 + + + 127.400 + + 6.597000 + + + 127.400 + + 6.587000 + + + 127.200 + + 6.364000 + + + 126.600 + + 6.783000 + + + 125.800 + + 6.783000 + + + 124.800 + + 6.765000 + + + 124.200 + + 6.765000 + + + 123.800 + + 6.765000 + + + 123.600 + + 6.877000 + + + 123.600 + + 6.895000 + + + 123.400 + + 6.914000 + + + 123.400 + + 6.914000 + + + 123.400 + + 6.914000 + + + 123.200 + + 6.821000 + + + 122.600 + + 6.662000 + + + 122.400 + + 6.662000 + + + 122.200 + + 6.653000 + + + 121.600 + + 6.653000 + + + 121.400 + + 6.653000 + + + 120.600 + + 6.615000 + + + 120.400 + + 6.615000 + + + 120.400 + + 6.522000 + + + 119.600 + + 7.007000 + + + 119.400 + + 7.007000 + + + 118.200 + + 7.091000 + + + 117.400 + + 7.147000 + + + 117.400 + + 7.147000 + + + 117.200 + + 7.091000 + + + 116.800 + + 7.091000 + + + 116.800 + + 7.091000 + + + 116.400 + + 6.802000 + + + 116.200 + + 6.606000 + + + 116.200 + + 6.578000 + + + 115.800 + + 5.953000 + + + 115.800 + + 6.364000 + + + 115.800 + + 5.309000 + + + 115.600 + + 6.205000 + + + 115.400 + + 6.205000 + + + 115.000 + + 6.205000 + + + 114.800 + + 6.895000 + + + 114.000 + + 7.269000 + + + 114.000 + + 7.259000 + + + 113.600 + + 6.998000 + + + 113.600 + + 6.998000 + + + 113.200 + + 7.045000 + + + 113.000 + + 7.073000 + + + 112.800 + + 7.026000 + + + 112.200 + + 7.455000 + + + 112.200 + + 6.522000 + + + 112.400 + + 6.522000 + + + 112.400 + + 6.513000 + + + 112.600 + + 6.298000 + + + 112.600 + + 6.336000 + + + 112.800 + + 6.298000 + + + 113.000 + + 6.298000 + + + 113.000 + + 6.298000 + + + 113.200 + + 6.336000 + + + 113.400 + + 6.503000 + + + 113.600 + + 6.476000 + + + 114.000 + + 6.476000 + + + 114.400 + + 6.476000 + + + 115.000 + + 6.550000 + + + 115.200 + + 6.550000 + + + 116.400 + + 6.550000 + + + 117.200 + + 5.682000 + + + 117.400 + + 5.682000 + + + 117.800 + + 5.944000 + + + 118.400 + + 4.824000 + + + 118.600 + + 4.787000 + + + 119.000 + + 3.387000 + + + 119.800 + + 2.043000 + + + 120.000 + + 0.000000 + + + + + 120.400 + + 1.717000 + + + 120.800 + + 1.717000 + + + 121.000 + + 2.090000 + + + 121.000 + + 1.698000 + + + 121.600 + + 0.000000 + + + + + 121.600 + + 1.661000 + + + 121.400 + + 1.642000 + + + + diff --git a/output/1718720200_activities.gpx b/output/1718720200_activities.gpx new file mode 100644 index 0000000..1aedc22 --- /dev/null +++ b/output/1718720200_activities.gpx @@ -0,0 +1,746 @@ + + + + + + LAP001 + LAP001 + LAP001 + + + + + 108.400 + + 6.578000 + + + 108.400 + + 6.578000 + + + 108.000 + + 6.578000 + + + 109.200 + + 6.485000 + + + 109.400 + + 6.485000 + + + 110.200 + + 6.401000 + + + 110.400 + + 6.392000 + + + 110.600 + + 6.392000 + + + 110.600 + + 6.354000 + + + 111.200 + + 6.354000 + + + 111.400 + + 6.354000 + + + 111.800 + + 6.354000 + + + 111.800 + + 6.317000 + + + 112.000 + + 6.261000 + + + 112.200 + + 6.261000 + + + 112.400 + + 6.140000 + + + 112.600 + + 6.140000 + + + 112.600 + + 6.140000 + + + 113.000 + + 6.186000 + + + 113.200 + + 6.252000 + + + 113.600 + + 6.336000 + + + 113.800 + + 6.410000 + + + 114.600 + + 6.476000 + + + 114.600 + + 6.522000 + + + 114.800 + + 6.522000 + + + 115.200 + + 6.466000 + + + 115.400 + + 6.457000 + + + 115.200 + + 6.354000 + + + 115.200 + + 6.289000 + + + 115.200 + + 6.102000 + + + 115.200 + + 6.084000 + + + 115.800 + + 6.084000 + + + 116.200 + + 5.981000 + + + 116.600 + + 5.860000 + + + 116.800 + + 5.645000 + + + 116.600 + + 5.645000 + + + 116.600 + + 5.645000 + + + 116.400 + + 5.748000 + + + 116.400 + + 6.289000 + + + 117.200 + + 6.326000 + + + 117.800 + + 6.326000 + + + 117.800 + + 6.326000 + + + 117.400 + + 6.354000 + + + 117.600 + + 6.354000 + + + 117.600 + + 6.224000 + + + 117.600 + + 6.121000 + + + 117.600 + + 5.860000 + + + 118.200 + + 4.749000 + + + 118.400 + + 4.749000 + + + 118.400 + + 5.291000 + + + 118.800 + + 5.468000 + + + 119.200 + + 5.374000 + + + 119.200 + + 5.365000 + + + 120.000 + + 6.811000 + + + 120.400 + + 7.735000 + + + 121.000 + + 8.127000 + + + 121.000 + + 7.866000 + + + 120.800 + + 7.539000 + + + 120.600 + + 7.539000 + + + 120.200 + + 7.437000 + + + 119.800 + + 7.269000 + + + 119.600 + + 7.101000 + + + 119.400 + + 6.998000 + + + 119.400 + + 6.998000 + + + 119.200 + + 6.793000 + + + 119.000 + + 6.755000 + + + 118.600 + + 6.737000 + + + 118.400 + + 6.494000 + + + 118.200 + + 5.953000 + + + 118.400 + + 6.280000 + + + 118.400 + + 6.438000 + + + 118.400 + + 6.438000 + + + 118.200 + + 6.438000 + + + 117.800 + + 6.559000 + + + 117.800 + + 6.578000 + + + 117.800 + + 6.578000 + + + 117.800 + + 6.559000 + + + 117.800 + + 6.559000 + + + 117.800 + + 6.448000 + + + 118.600 + + 6.018000 + + + 119.200 + + 6.018000 + + + 119.600 + + 5.990000 + + + 119.800 + + 5.832000 + + + 120.200 + + 5.057000 + + + 120.200 + + 5.580000 + + + 119.600 + + 6.149000 + + + 119.200 + + 6.513000 + + + 119.000 + + 6.541000 + + + 118.400 + + 6.149000 + + + 118.000 + + 6.448000 + + + 117.800 + + 6.867000 + + + 117.200 + + 7.931000 + + + 115.800 + + 8.006000 + + + 114.800 + + 6.709000 + + + 114.400 + + 5.962000 + + + 113.800 + + 4.647000 + + + 113.000 + + 3.630000 + + + 112.400 + + 5.188000 + + + 112.400 + + 4.283000 + + + 112.600 + + 3.807000 + + + 111.600 + + 5.029000 + + + 110.800 + + 6.326000 + + + 110.200 + + 7.567000 + + + 109.800 + + 7.931000 + + + 109.600 + + 8.099000 + + + 108.400 + + 8.043000 + + + 108.000 + + 7.931000 + + + 107.600 + + 8.099000 + + + 107.200 + + 8.099000 + + + 106.400 + + 8.099000 + + + 106.200 + + 8.071000 + + + 105.600 + + 7.521000 + + + 105.400 + + 6.476000 + + + 105.000 + + 5.384000 + + + 104.200 + + 2.631000 + + + 104.000 + + 2.165000 + + + 103.800 + + 1.316000 + + + 103.800 + + 1.306000 + + + 103.600 + + 1.316000 + + + 103.600 + + 1.306000 + + + 103.400 + + 1.316000 + + + 103.200 + + 5.160000 + + + 103.000 + + 5.505000 + + + 103.000 + + 5.160000 + + + 102.800 + + 5.169000 + + + 102.400 + + 6.392000 + + + 102.400 + + 6.802000 + + + 102.200 + + 7.483000 + + + 101.600 + + 7.390000 + + + 101.200 + + 7.241000 + + + 100.000 + + 7.241000 + + + 98.600 + + 6.793000 + + + 98.600 + + 2.463000 + + + 99.000 + + 1.708000 + + + 99.000 + + 2.370000 + + + 98.600 + + 1.008000 + + + 98.400 + + 1.008000 + + + 98.400 + + 1.232000 + + + 98.200 + + 1.008000 + + + 98.200 + + 0.998000 + + + 98.200 + + 1.008000 + + + 98.000 + + 1.082000 + + + 98.000 + + 0.000000 + + + + + 98.200 + + 1.633000 + + + 98.200 + + 1.260000 + + + 98.200 + + 1.260000 + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8009003 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask==2.2.5 +Werkzeug==2.2.3 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..7b3a048 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,133 @@ + + + + + + FIT to GPX Converter + + + + + +
+
+

FIT to GPX Converter

+

Convert your .fit files to .gpx format with ease!

+
+ +
+ + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + +
+
+ + +
+
+ +
+
+

Input Files:

+ {% if input_files %} +
    + {% for file in input_files %} +
  • + + {{ file }} +
  • + {% endfor %} +
+ + {% else %} +

No input files yet. Upload a .fit file to get started!

+ {% endif %} +
+ +
+

Output Files:

+ {% if output_files %} +
    + {% for file in output_files %} +
  • + + {{ file }} +
  • + {% endfor %} +
+ + {% else %} +

No converted files yet. Upload a .fit file to get started!

+ {% endif %} +
+
+
+
+ +