-
Notifications
You must be signed in to change notification settings - Fork 1
/
moovplot.py
executable file
·113 lines (95 loc) · 3.2 KB
/
moovplot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env python
import zlib
import sys
import io
import tarfile
import sqlite3
import tempfile
import json
import argparse
import subprocess
argp = argparse.ArgumentParser(description="moov csv and plot")
argp.add_argument("--csv", action="store_true", help="output to csv")
argp.add_argument("--sqlite", action="store_true", help="launch sqlite shell for exploring")
argp.add_argument("-b", action="store_true", help="generate a backup to use")
argp.add_argument("FILE", nargs="?", default="", help="android backup file")
args = argp.parse_args()
#sys.exit(1)
''' reads android archive and returns a tempfile of the sqlite db'''
def readfile(path):
f = open(path, "r+b")
# im not sure why skip the first 24 bytes
# something about how android zips the tarball
f.seek(24)
#unzip
buf = io.BytesIO(zlib.decompress(f.read()))
tar = tarfile.open(0, "r", buf)
# extract sqlite databases from archive
dbtar = None
tmpf = tempfile.NamedTemporaryFile()
for member in tar.getmembers():
if not member.name.startswith("apps/cc.moov.one/"):
continue
if member.name.endswith("user.db"):
dbtar = tar.extractfile(member)
tmpf.write(dbtar.read())
dbtar.close()
break
if dbtar == None:
raise Exception("failed finding user.db in archive")
f.close()
buf.close()
tar.close()
tmpf.flush()
return tmpf
''' moov seems to store data some data in json blobs we attempt to decode into
json if we see a str and select the fields. otherwise we simply print the field'''
def query(sql, q, fields):
sql.execute(q)
print(",".join(fields))
for r in sql.fetchall():
for col in r:
for f in fields:
# first try to get the field from json
if type(col) == str:
js = json.loads(col)
if f in js:
print("%s," % js[f], end="")
continue
# failed to get this col from json, try from the row
try:
print("%s," % r[f], end="")
except IndexError:
pass
print()
if args.FILE == "" and not args.b:
argp.error("either specify a backup file or the -b option")
bkfile = args.FILE
if args.b:
tmpf = tempfile.NamedTemporaryFile()
subprocess.run(["adb", "backup", "-f", tmpf.name, "-noapk", "cc.moov.one"])
bkfile = tmpf.name
dbfile = readfile(bkfile)
if args.sqlite:
subprocess.run(["/usr/bin/sqlite3", dbfile.name])
if args.csv:
conn = sqlite3.connect(dbfile.name)
conn.row_factory = sqlite3.Row
sql = conn.cursor()
print("\n\nswims:")
query(sql,
"SELECT duration,program_specific_data, local_cache FROM workouts WHERE workout_type = 2",
["duration",
"lap_count",
"stroke_count",
"distance",
"distance_per_stroke",
"stroke_rate"])
print("\n\nruns:")
query(sql,
"SELECT duration,local_cache FROM workouts WHERE workout_type = 0",
["duration",
"average_cadence",
"average_speed",
"distance"])
sql.close()