Skip to content

Commit

Permalink
Add support for Google Takeout Location History (#1160)
Browse files Browse the repository at this point in the history
* Add support for Google Takeout Location History

This adds support for parsing the location history provided by Google Takeout.
This makes it possible to convert a month's, year's, or your entire location
history at once instead of having to export one day's history at a time on
Google Maps.

There is documentation in the `xmldoc` folder with some examples.

It works great, but there are one, possibly two, other additions I'd like to
make in following diffs:

1. Add the ability to select date ranges. For example, I went on a road trip
   that started in the last week of February, but right now I can only select
	 tracks at the resolution of a whole month.

2. Add support for the higher-resolution "roadSegment" blocks in newer
   "activitySegment" blocks. This will have to be optional as you have to
	 query the Google Maps API to get lat/long, which costs money. However,
	 if you're willing to pay for it, you can get great detail out of it.
	 They look like this:

```
       "roadSegment": [{
          "placeId": "ChIJBdXmuuWaK4gRoiClERhZcy8",
          "duration": "76s"
        }, {
          "placeId": "ChIJ4ekNlOWaK4gRxu-moMRFo60",
          "duration": "58s"
        }, {
          "placeId": "ChIJ10qEheWaK4gRQ1T24wEuuN4",
          "duration": "58s"
        }, {
          "placeId": "ChIJe7NWfu-aK4gRFHBB6P0PMe4",
          "duration": "58s"
[...]
```

* rename variable

* this TODO is done

* now builds on focal, fix documentation

* patch -p2 < ~/testo.log

* use `&&` instead of `and` for old compilers

* don't leak objects when we skip events at exact lat/lon 0/0

* use a reference (even though the compiler would have optimized that away)

* rename to googletakeout

* fix docs

* Address code review requests

* add `googletakeout.h` to HEADERS
* convert most `#define`s to static members
* don't pollute global namespace
* rename logging functions
* convert some methods to static functions for clang-tidy
* `title_case` loop by reference instead of by index (clang-tidy)
* better use of debugging levels
* drop dead simplifiedRawPath code for now
* drop empty tracks
* default constructor for GoogleTakeoutInputStream
* add some tests that check the content of the data

Also, I found some unofficial documentation about the location history
format and added that (thanks @CarlosBergillos !)

* apply @tsteven4 's patch. thank you!!

* add license

* fix logging

* As I assigned the correct license to my code, I am skeptical that this makes a difference, but give Robert co-copyright.

* make the test more boring

* rm xml_slice

* revert constructor change from @tsteven4 's patch

* apply @tsteven4 's latest constructor

* apply @tsteven4 's latest patch -- `cmake --build . --target check` passes

---------

Co-authored-by: tsteven4 <[email protected]>
  • Loading branch information
2 people authored and robertlipe committed Aug 12, 2024
1 parent 2098c61 commit 916a591
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 53 deletions.
62 changes: 30 additions & 32 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
*.a
*.o
*.swp
.ninja_deps
.ninja_log
.qmake.cache
.qmake.stash
.qt
/*.gcda
/*.gcno
/*.gcov
/.vs/
/.vscode/
/GPSBabel
/GPSBabel[0-9]*.[0-9]*.[0-9]*.tar.bz2
/GPSBabel[0-9]*.[0-9]*.[0-9]*/
/Makefile
/autogen/
/autom4te.cache/
/babelweb/
/bld/
Expand All @@ -26,30 +8,46 @@
/config.status
/cscope.out
/debug/
/empty
/gbversion.h
/gpsbabel
/gpsbabel-debug
/gpsbabel.exe
/gpsbabel.fo
/gpsbabel.gch/
/gpsbabel.html
/gpsbabel.pdf
/gpsbabel.rc
/gpsbabel_autogen/
/gpsbabel_coverage.xml
/makedoc
/Makefile
.qmake.cache
.qmake.stash
/GPSBabel
/*.gcda
/*.gcno
/*.gcov
*.o
*.a
.ninja_deps
.ninja_log
.qt
build.ninja
rules.ninja
cmake_install.cmake
CMakeCache.txt
CMakeFiles/
CTestTestfile.cmake
/GPSBabel[0-9]*.[0-9]*.[0-9]*/
/GPSBabel[0-9]*.[0-9]*.[0-9]*.tar.bz2
/makelinuxdist.sh
/mkcapabilities
/objects/
/out/
/qrc_gpsbabel.cpp
/release/
*.swp
/tmp/
CMakeCache.txt
CMakeFiles/
CTestTestfile.cmake
/mkcapabilities
/gpsbabel.gch/
/gpsbabel.rc
/autogen/
/makedoc
/empty
/gbversion.h
/qrc_gpsbabel.cpp
/.vscode/
Testing
build.ninja
cmake_install.cmake
rules.ninja
19 changes: 11 additions & 8 deletions googletakeout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ static const QList<QString> takeout_month_names{
"AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
};

static void takeout_fatal(const QString& message) {
static inline void takeout_fatal(const QString& message) {
fatal(FatalMsg() << MYNAME << ": " << message);
}

static void takeout_warning(const QString& message) {
static inline void takeout_warning(const QString& message) {
Warning() << MYNAME << ": " << message;
}

Expand All @@ -68,13 +68,13 @@ static Waypoint* takeout_waypoint(
Waypoint* waypoint = new Waypoint();
waypoint->latitude = lat_e7 / 1e7;
waypoint->longitude = lon_e7 / 1e7;
if (shortname && shortname->length() > 0) {
if (shortname && (*shortname).length() > 0) {
waypoint->shortname = *shortname;
}
if (description && description->length() > 0) {
if (description && (*description).length() > 0) {
waypoint->description = *description;
}
if (start_str && start_str->length() > 0) {
if (start_str && (*start_str).length() > 0) {
gpsbabel::DateTime start = QDateTime::fromString(*start_str, Qt::ISODate);
waypoint->SetCreationTime(start);
}
Expand Down Expand Up @@ -217,13 +217,16 @@ GoogleTakeoutFormat::title_case(QString& title)
}

void
GoogleTakeoutFormat::read()
{
GoogleTakeoutFormat::rd_init(const QString& fname) {
if (global_opts.debug_level >= 4) {
Debug(4) << "rd_init(" << fname << ")";
}
GoogleTakeoutInputStream inputStream(fname);
inputStream = GoogleTakeoutInputStream(fname);
}

void
GoogleTakeoutFormat::read()
{
int items = 0;
int points = 0;
int place_visits = 0;
Expand Down
18 changes: 8 additions & 10 deletions googletakeout.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
*/
#ifndef GOOGLETAKEOUT_H_INCLUDED_
#define GOOGLETAKEOUT_H_INCLUDED_
#ifndef _GOOGLETAKEOUT_H
#define _GOOGLETAKEOUT_H

#include <QJsonObject> // for QJsonObject
#include <QJsonValue> // for QJsonValue
Expand All @@ -43,7 +43,7 @@ class GoogleTakeoutInputStream
public:
/* Special Member Functions */
GoogleTakeoutInputStream() = default;
GoogleTakeoutInputStream(const QString& source) : sources({source}) {}
GoogleTakeoutInputStream(const QString& source) : sources({source}) {};

/* Member Functions */

Expand All @@ -65,8 +65,6 @@ class GoogleTakeoutInputStream
class GoogleTakeoutFormat : public Format
{
public:
using Format::Format;

/* Member functions */
QVector<arglist_t>* get_args() override
{
Expand All @@ -75,18 +73,17 @@ class GoogleTakeoutFormat : public Format

ff_type get_type() const override
{
return ff_type_file;
return ff_type_file;
}

QVector<ff_cap> get_cap() const override
{
return { ff_cap_read, ff_cap_read, ff_cap_none };
}

void rd_init(const QString& fname) override
{}
void rd_init(const QString& fname) override;
void read() override;

private:
/* Constants */

Expand Down Expand Up @@ -122,7 +119,8 @@ class GoogleTakeoutFormat : public Format

/* Data Members */

GoogleTakeoutInputStream inputStream;
QVector<arglist_t> googletakeout_args;
};

#endif /* GOOGLETAKEOUT_H_INCLUDED_ */
#endif /* _GOOGLETAKEOUT_H */
6 changes: 3 additions & 3 deletions vecs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ struct Vecs::Impl {
GeoJsonFormat geojson_fmt;
GlobalsatSportFormat globalsat_sport_fmt;
QstarzBL1000Format qstarz_bl_1000_fmt;
GoogleTakeoutFormat google_timeline_fmt;
#endif // MAXIMAL_ENABLED

const QVector<vecs_t> vec_list {
Expand Down Expand Up @@ -494,12 +495,11 @@ struct Vecs::Impl {
nullptr,
},
{
nullptr,
&google_timeline_fmt,
"googletakeout",
"Google Takeout Location History",
"json",
nullptr,
&fmtfactory<GoogleTakeoutFormat>
}
#endif // MAXIMAL_ENABLED
};
Expand Down Expand Up @@ -817,7 +817,7 @@ Vecs::fmtinfo_t Vecs::find_vec(const QString& fmtargstring)
* Didn't find it in the table of "real" file types, so plan B
* is to search the list of xcsv styles.
*/
for (const auto& svec : std::as_const(style_list)) {
for (const auto& svec : qAsConst(style_list)) {
if (fmtname.compare(svec.name, Qt::CaseInsensitive) != 0) {
continue;
}
Expand Down

0 comments on commit 916a591

Please sign in to comment.