# Route Packager — OsmAnd + Google KMZ This package contains `route_packager.py`, a Python CLI for the scraped route archive tree in `v4-scrape-675.tar.gz`. ## What it does - Scans the canonical `downloads_by_hash/` folder by default, avoiding retry/failure duplicate folders. - Extracts ZIP, RAR, 7Z payloads. - Imports GPX, KML, KMZ routes directly. - Converts Garmin GDB to GPX when `gpsbabel` is installed. - Carries over scrape metadata from `*.source.json` into route descriptions and reports. - Carries over small text files into route descriptions. - Embeds image files into the KMZ and OSF package under `media/...` and references them from descriptions. - Writes machine-readable `report.json` and `routes.csv` for validation/pre-push review. ## Outputs Default command creates all of these: - `.osmand-tracks.osf` — OsmAnd package/zip containing normalized GPX tracks. - `.all-routes.gpx` — fallback aggregate GPX for OsmAnd if the OSF package import is not accepted by a particular build. - `.google-earth-maps.kmz` — binary zipped KML package for Google My Maps / Google Earth. - `.google-earth-maps.kml` — plain KML fallback. - `.report.json` — full import/skip/warning report. - `.routes.csv` — route list with source archive, point count, distance, bbox, etc. ## Install extraction/conversion tools The script itself is stdlib-only for ZIP/KML/KMZ/GPX. RAR and GDB need external tools: ```bash sudo apt update sudo apt install p7zip-full unrar-free gpsbabel ``` If `unrar-free` fails on some RAR versions, install one of `unrar`, `unar`, or `bsdtar` depending on your distro. ## Full run ```bash python3 route_packager.py \ --input ./v4-scrape-675.tar.gz \ --out ./route-out \ --target both \ --name bg-mountain-routes \ --verbose ``` ## Google My Maps one-file safe mode Google My Maps has a small uncompressed KML/KMZ import ceiling. For a single importable KMZ, use safe mode. It simplifies only the Google output; OsmAnd keeps full GPX detail. ```bash python3 route_packager.py \ --input ./v4-scrape-675.tar.gz \ --out ./route-out-google-safe \ --target google \ --name bg-mountain-routes \ --google-my-maps-safe ``` Manual geometry cap if needed: ```bash python3 route_packager.py --input ./v4-scrape-675.tar.gz --out ./out --target google \ --google-max-points-per-route 500 --google-lean-descriptions ``` ## ZIP-only validation without RAR tooling ```bash python3 route_packager.py \ --input ./v4-scrape-675.tar.gz \ --out ./route-out-zip-only \ --target both \ --skip-rar \ --name bg-mountain-routes-zip-only ``` ## Strict CI/pre-push mode ```bash python3 route_packager.py \ --input ./v4-scrape-675.tar.gz \ --out ./route-out \ --target both \ --name bg-mountain-routes \ --strict ``` `--strict` exits non-zero if RARs/GDBs fail to import. ## Validation commands ```bash python3 -m py_compile route_packager.py python3 route_packager.py --input ./v4-scrape-675.tar.gz --out ./out --target both --skip-rar --name smoke python3 - <<'PY' from pathlib import Path import zipfile, xml.etree.ElementTree as ET out = Path('./out') for name in ['smoke.osmand-tracks.osf', 'smoke.google-earth-maps.kmz']: with zipfile.ZipFile(out / name) as z: assert z.testzip() is None, name ET.parse(out / 'smoke.all-routes.gpx') with zipfile.ZipFile(out / 'smoke.google-earth-maps.kmz') as z: ET.fromstring(z.read('doc.kml')) print('OK') PY ``` ## Format note There is no arbitrary custom binary route format for Google Maps imports. KMZ is the practical binary container because it is zipped KML and can include images/media. For OsmAnd, the script emits an OSF-style package plus a GPX fallback because GPX is OsmAnd's most predictable track import path.