mapillary-downloader 0.1.3__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapillary_downloader
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: Download your Mapillary data before it's gone
5
5
  Author-email: Gareth Davidson <gaz@bitplane.net>
6
6
  Requires-Python: >=3.10
@@ -59,6 +59,7 @@ mapillary-downloader --token YOUR_TOKEN --username YOUR_USERNAME --output ./down
59
59
  | `--output` | Output directory | `./mapillary_data` |
60
60
  | `--quality` | 256, 1024, 2048 or original | `original` |
61
61
  | `--bbox` | `west,south,east,north` | `None` |
62
+ | `--webp` | Convert to WebP (saves ~70% space) | `False` |
62
63
 
63
64
  The downloader will:
64
65
 
@@ -67,6 +68,26 @@ The downloader will:
67
68
  * 📜 Inject EXIF metadata (GPS coordinates, camera info, timestamps,
68
69
  compass direction)
69
70
  * 🛟 Save progress so you can safely resume if interrupted
71
+ * 🗜️ Optionally convert to WebP format for massive space savings
72
+
73
+ ## WebP Conversion
74
+
75
+ Use the `--webp` flag to convert images to WebP format after download:
76
+
77
+ ```bash
78
+ mapillary-downloader --token YOUR_TOKEN --username YOUR_USERNAME --webp
79
+ ```
80
+
81
+ This reduces storage by approximately 70% while preserving all EXIF metadata
82
+ including GPS coordinates. Requires the `cwebp` binary to be installed:
83
+
84
+ ```bash
85
+ # Debian/Ubuntu
86
+ sudo apt install webp
87
+
88
+ # macOS
89
+ brew install webp
90
+ ```
70
91
 
71
92
  ## Development
72
93
 
@@ -29,6 +29,7 @@ mapillary-downloader --token YOUR_TOKEN --username YOUR_USERNAME --output ./down
29
29
  | `--output` | Output directory | `./mapillary_data` |
30
30
  | `--quality` | 256, 1024, 2048 or original | `original` |
31
31
  | `--bbox` | `west,south,east,north` | `None` |
32
+ | `--webp` | Convert to WebP (saves ~70% space) | `False` |
32
33
 
33
34
  The downloader will:
34
35
 
@@ -37,6 +38,26 @@ The downloader will:
37
38
  * 📜 Inject EXIF metadata (GPS coordinates, camera info, timestamps,
38
39
  compass direction)
39
40
  * 🛟 Save progress so you can safely resume if interrupted
41
+ * 🗜️ Optionally convert to WebP format for massive space savings
42
+
43
+ ## WebP Conversion
44
+
45
+ Use the `--webp` flag to convert images to WebP format after download:
46
+
47
+ ```bash
48
+ mapillary-downloader --token YOUR_TOKEN --username YOUR_USERNAME --webp
49
+ ```
50
+
51
+ This reduces storage by approximately 70% while preserving all EXIF metadata
52
+ including GPS coordinates. Requires the `cwebp` binary to be installed:
53
+
54
+ ```bash
55
+ # Debian/Ubuntu
56
+ sudo apt install webp
57
+
58
+ # macOS
59
+ brew install webp
60
+ ```
40
61
 
41
62
  ## Development
42
63
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "mapillary_downloader"
3
3
  description = "Download your Mapillary data before it's gone"
4
- version = "0.1.3"
4
+ version = "0.2.0"
5
5
  authors = [
6
6
  { name = "Gareth Davidson", email = "gaz@bitplane.net" }
7
7
  ]
@@ -5,6 +5,7 @@ import sys
5
5
  from mapillary_downloader.client import MapillaryClient
6
6
  from mapillary_downloader.downloader import MapillaryDownloader
7
7
  from mapillary_downloader.logging_config import setup_logging
8
+ from mapillary_downloader.webp_converter import check_cwebp_available
8
9
 
9
10
 
10
11
  def main():
@@ -23,6 +24,11 @@ def main():
23
24
  help="Image quality to download (default: original)",
24
25
  )
25
26
  parser.add_argument("--bbox", help="Bounding box: west,south,east,north")
27
+ parser.add_argument(
28
+ "--webp",
29
+ action="store_true",
30
+ help="Convert images to WebP format (saves ~70%% disk space, requires cwebp binary)",
31
+ )
26
32
 
27
33
  args = parser.parse_args()
28
34
 
@@ -36,10 +42,17 @@ def main():
36
42
  logger.error("Error: bbox must be four comma-separated numbers")
37
43
  sys.exit(1)
38
44
 
45
+ # Check for cwebp binary if WebP conversion is requested
46
+ if args.webp:
47
+ if not check_cwebp_available():
48
+ logger.error("Error: cwebp binary not found. Install webp package (e.g., apt install webp)")
49
+ sys.exit(1)
50
+ logger.info("WebP conversion enabled - images will be converted after download")
51
+
39
52
  try:
40
53
  client = MapillaryClient(args.token)
41
54
  downloader = MapillaryDownloader(client, args.output)
42
- downloader.download_user_data(args.username, args.quality, bbox)
55
+ downloader.download_user_data(args.username, args.quality, bbox, convert_webp=args.webp)
43
56
  except KeyboardInterrupt:
44
57
  logger.info("\nInterrupted by user")
45
58
  sys.exit(1)
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from collections import deque
9
9
  from mapillary_downloader.exif_writer import write_exif_to_image
10
10
  from mapillary_downloader.utils import format_size, format_time
11
+ from mapillary_downloader.webp_converter import convert_to_webp
11
12
 
12
13
  logger = logging.getLogger("mapillary_downloader")
13
14
 
@@ -46,13 +47,14 @@ class MapillaryDownloader:
46
47
  os.fsync(f.fileno())
47
48
  temp_file.replace(self.progress_file)
48
49
 
49
- def download_user_data(self, username, quality="original", bbox=None):
50
+ def download_user_data(self, username, quality="original", bbox=None, convert_webp=False):
50
51
  """Download all images for a user.
51
52
 
52
53
  Args:
53
54
  username: Mapillary username
54
55
  quality: Image quality to download (256, 1024, 2048, original)
55
56
  bbox: Optional bounding box [west, south, east, north]
57
+ convert_webp: Convert images to WebP format after download
56
58
  """
57
59
  quality_field = f"thumb_{quality}_url"
58
60
 
@@ -110,6 +112,12 @@ class MapillaryDownloader:
110
112
 
111
113
  write_exif_to_image(output_path, image)
112
114
 
115
+ # Convert to WebP if requested
116
+ if convert_webp:
117
+ webp_path = convert_to_webp(output_path)
118
+ if webp_path:
119
+ output_path = webp_path
120
+
113
121
  self.downloaded.add(image_id)
114
122
  downloaded_count += 1
115
123
  total_bytes += bytes_downloaded
@@ -169,6 +177,12 @@ class MapillaryDownloader:
169
177
  # Write EXIF metadata to the downloaded image
170
178
  write_exif_to_image(output_path, image)
171
179
 
180
+ # Convert to WebP if requested
181
+ if convert_webp:
182
+ webp_path = convert_to_webp(output_path)
183
+ if webp_path:
184
+ output_path = webp_path
185
+
172
186
  self.downloaded.add(image_id)
173
187
  downloaded_count += 1
174
188
  total_bytes += bytes_downloaded
@@ -0,0 +1,54 @@
1
+ """WebP image conversion utilities."""
2
+
3
+ import logging
4
+ import shutil
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ logger = logging.getLogger("mapillary_downloader")
9
+
10
+
11
+ def check_cwebp_available():
12
+ """Check if cwebp binary is available.
13
+
14
+ Returns:
15
+ bool: True if cwebp is found, False otherwise
16
+ """
17
+ return shutil.which("cwebp") is not None
18
+
19
+
20
+ def convert_to_webp(jpg_path):
21
+ """Convert a JPG image to WebP format, preserving EXIF metadata.
22
+
23
+ Args:
24
+ jpg_path: Path to the JPG file
25
+
26
+ Returns:
27
+ Path object to the new WebP file, or None if conversion failed
28
+ """
29
+ jpg_path = Path(jpg_path)
30
+ webp_path = jpg_path.with_suffix(".webp")
31
+
32
+ try:
33
+ # Convert with cwebp, preserving all metadata
34
+ result = subprocess.run(
35
+ ["cwebp", "-metadata", "all", str(jpg_path), "-o", str(webp_path)],
36
+ capture_output=True,
37
+ text=True,
38
+ timeout=60,
39
+ )
40
+
41
+ if result.returncode != 0:
42
+ logger.error(f"cwebp conversion failed for {jpg_path}: {result.stderr}")
43
+ return None
44
+
45
+ # Delete original JPG after successful conversion
46
+ jpg_path.unlink()
47
+ return webp_path
48
+
49
+ except subprocess.TimeoutExpired:
50
+ logger.error(f"cwebp conversion timed out for {jpg_path}")
51
+ return None
52
+ except Exception as e:
53
+ logger.error(f"Error converting {jpg_path} to WebP: {e}")
54
+ return None