mapillary-tools 0.14.0a2__py3-none-any.whl → 0.14.1__py3-none-any.whl

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.
Files changed (49) hide show
  1. mapillary_tools/__init__.py +1 -1
  2. mapillary_tools/api_v4.py +66 -262
  3. mapillary_tools/authenticate.py +54 -46
  4. mapillary_tools/blackvue_parser.py +79 -22
  5. mapillary_tools/commands/__main__.py +15 -16
  6. mapillary_tools/commands/upload.py +33 -4
  7. mapillary_tools/config.py +38 -17
  8. mapillary_tools/constants.py +127 -43
  9. mapillary_tools/exceptions.py +4 -0
  10. mapillary_tools/exif_read.py +2 -1
  11. mapillary_tools/exif_write.py +3 -1
  12. mapillary_tools/exiftool_read_video.py +52 -15
  13. mapillary_tools/exiftool_runner.py +4 -24
  14. mapillary_tools/ffmpeg.py +406 -232
  15. mapillary_tools/geo.py +16 -0
  16. mapillary_tools/geotag/__init__.py +0 -0
  17. mapillary_tools/geotag/base.py +8 -4
  18. mapillary_tools/geotag/factory.py +106 -89
  19. mapillary_tools/geotag/geotag_images_from_exiftool.py +27 -20
  20. mapillary_tools/geotag/geotag_images_from_gpx.py +7 -6
  21. mapillary_tools/geotag/geotag_images_from_video.py +35 -0
  22. mapillary_tools/geotag/geotag_videos_from_exiftool.py +61 -14
  23. mapillary_tools/geotag/geotag_videos_from_gpx.py +22 -9
  24. mapillary_tools/geotag/options.py +25 -3
  25. mapillary_tools/geotag/utils.py +9 -12
  26. mapillary_tools/geotag/video_extractors/base.py +1 -1
  27. mapillary_tools/geotag/video_extractors/exiftool.py +1 -1
  28. mapillary_tools/geotag/video_extractors/gpx.py +61 -70
  29. mapillary_tools/geotag/video_extractors/native.py +34 -31
  30. mapillary_tools/history.py +128 -8
  31. mapillary_tools/http.py +211 -0
  32. mapillary_tools/mp4/construct_mp4_parser.py +8 -2
  33. mapillary_tools/process_geotag_properties.py +47 -35
  34. mapillary_tools/process_sequence_properties.py +340 -325
  35. mapillary_tools/sample_video.py +8 -8
  36. mapillary_tools/serializer/description.py +587 -0
  37. mapillary_tools/serializer/gpx.py +132 -0
  38. mapillary_tools/types.py +44 -610
  39. mapillary_tools/upload.py +327 -352
  40. mapillary_tools/upload_api_v4.py +125 -72
  41. mapillary_tools/uploader.py +797 -216
  42. mapillary_tools/utils.py +57 -5
  43. {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/METADATA +91 -34
  44. mapillary_tools-0.14.1.dist-info/RECORD +76 -0
  45. {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/WHEEL +1 -1
  46. mapillary_tools-0.14.0a2.dist-info/RECORD +0 -72
  47. {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/entry_points.txt +0 -0
  48. {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/licenses/LICENSE +0 -0
  49. {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,132 @@
1
+ import datetime
2
+ import json
3
+ import sys
4
+ import typing as T
5
+
6
+ if sys.version_info >= (3, 12):
7
+ from typing import override
8
+ else:
9
+ from typing_extensions import override
10
+
11
+ import gpxpy
12
+ import gpxpy.gpx
13
+
14
+ from .. import geo, types
15
+
16
+ from ..telemetry import CAMMGPSPoint, GPSPoint
17
+ from ..types import (
18
+ BaseSerializer,
19
+ ErrorMetadata,
20
+ ImageMetadata,
21
+ MetadataOrError,
22
+ VideoMetadata,
23
+ )
24
+ from .description import DescriptionJSONSerializer
25
+
26
+
27
+ class GPXSerializer(BaseSerializer):
28
+ @override
29
+ @classmethod
30
+ def serialize(cls, metadatas: T.Sequence[MetadataOrError]) -> bytes:
31
+ gpx = cls.as_gpx(metadatas)
32
+ return gpx.to_xml().encode("utf-8")
33
+
34
+ @classmethod
35
+ def as_gpx(cls, metadatas: T.Sequence[MetadataOrError]) -> gpxpy.gpx.GPX:
36
+ gpx = gpxpy.gpx.GPX()
37
+
38
+ error_metadatas = []
39
+ image_metadatas = []
40
+ video_metadatas = []
41
+
42
+ for metadata in metadatas:
43
+ if isinstance(metadata, ErrorMetadata):
44
+ error_metadatas.append(metadata)
45
+ elif isinstance(metadata, ImageMetadata):
46
+ image_metadatas.append(metadata)
47
+ elif isinstance(metadata, VideoMetadata):
48
+ video_metadatas.append(metadata)
49
+
50
+ for metadata in error_metadatas:
51
+ gpx_track = gpxpy.gpx.GPXTrack()
52
+ gpx_track.name = str(metadata.filename)
53
+ gpx_track.description = cls._build_gpx_description(metadata, ["filename"])
54
+ gpx.tracks.append(gpx_track)
55
+
56
+ sequences = types.group_and_sort_images(image_metadatas)
57
+ for sequence_uuid, sequence in sequences.items():
58
+ gpx.tracks.append(cls.image_sequence_as_gpx_track(sequence_uuid, sequence))
59
+
60
+ for metadata in video_metadatas:
61
+ gpx.tracks.append(cls.as_gpx_track(metadata))
62
+
63
+ return gpx
64
+
65
+ @classmethod
66
+ def as_gpx_point(cls, point: geo.Point) -> gpxpy.gpx.GPXTrackPoint:
67
+ gpx_point = gpxpy.gpx.GPXTrackPoint(
68
+ latitude=point.lat,
69
+ longitude=point.lon,
70
+ elevation=point.alt,
71
+ time=datetime.datetime.fromtimestamp(point.time, datetime.timezone.utc),
72
+ )
73
+
74
+ if isinstance(point, types.ImageMetadata):
75
+ gpx_point.name = point.filename.name
76
+ elif isinstance(point, CAMMGPSPoint):
77
+ gpx_point.time = datetime.datetime.fromtimestamp(
78
+ point.time_gps_epoch, datetime.timezone.utc
79
+ )
80
+ elif isinstance(point, GPSPoint):
81
+ if point.epoch_time is not None:
82
+ gpx_point.time = datetime.datetime.fromtimestamp(
83
+ point.epoch_time, datetime.timezone.utc
84
+ )
85
+
86
+ return gpx_point
87
+
88
+ @classmethod
89
+ def as_gpx_track(cls, metadata: VideoMetadata) -> gpxpy.gpx.GPXTrack:
90
+ gpx_segment = gpxpy.gpx.GPXTrackSegment()
91
+ for point in metadata.points:
92
+ gpx_point = cls.as_gpx_point(point)
93
+ gpx_segment.points.append(gpx_point)
94
+ gpx_track = gpxpy.gpx.GPXTrack()
95
+ gpx_track.name = str(metadata.filename)
96
+ gpx_track.description = cls._build_gpx_description(
97
+ metadata, ["filename", "MAPGPSTrack"]
98
+ )
99
+ gpx_track.segments.append(gpx_segment)
100
+ return gpx_track
101
+
102
+ @classmethod
103
+ def image_sequence_as_gpx_track(
104
+ cls, sequence_uuid: str, sequence: T.Sequence[ImageMetadata]
105
+ ) -> gpxpy.gpx.GPXTrack:
106
+ gpx_segment = gpxpy.gpx.GPXTrackSegment()
107
+ for metadata in sequence:
108
+ gpx_point = cls.as_gpx_point(metadata)
109
+ gpx_segment.points.append(gpx_point)
110
+ gpx_track = gpxpy.gpx.GPXTrack()
111
+ gpx_track.name = sequence_uuid
112
+ gpx_track.description = cls._build_gpx_description(
113
+ metadata,
114
+ [
115
+ "filename",
116
+ "MAPLongitude",
117
+ "MAPLatitude",
118
+ "MAPCaptureTime",
119
+ "MAPAltitude",
120
+ ],
121
+ )
122
+ gpx_track.segments.append(gpx_segment)
123
+ return gpx_track
124
+
125
+ @classmethod
126
+ def _build_gpx_description(
127
+ cls, metadata: MetadataOrError, excluded_properties: T.Sequence[str]
128
+ ) -> str:
129
+ desc = T.cast(T.Dict, DescriptionJSONSerializer.as_desc(metadata))
130
+ for prop in excluded_properties:
131
+ desc.pop(prop, None)
132
+ return json.dumps(desc, sort_keys=True, separators=(",", ":"))