#!/usr/bin/env python3 """Total time tagged language:spanish in Traggo, as decimal hours.""" import json import subprocess import sys import urllib.request from collections import defaultdict from datetime import datetime, timezone URL = "https://time.rcjohnstone.com/graphql" USER = "connor" def gql(query, cookie=None): req = urllib.request.Request( URL, data=json.dumps({"query": query}).encode(), headers={"Content-Type": "application/json"}, ) if cookie: req.add_header("Cookie", f"traggo={cookie}") body = json.load(urllib.request.urlopen(req)) if body.get("errors"): sys.exit(f"traggo: {body['errors'][0]['message']}") return body["data"] def login(): pw = subprocess.run( ["rbw", "get", "Traggo"], capture_output=True, text=True, check=True ).stdout.strip() data = gql( 'mutation{login(username:"%s",pass:%s,deviceName:"spanish-time",' "type:LongExpiry,cookie:false){token}}" % (USER, json.dumps(pw)) ) return data["login"]["token"] def spans(token): offset, start_id = 0, None while True: cur = f"offset:{offset},pageSize:200" if start_id is not None: cur += f",startId:{start_id}" data = gql( '{timeSpans(fromInclusive:"2000-01-01T00:00:00Z",' 'toInclusive:"2100-01-01T00:00:00Z",cursor:{%s})' "{cursor{hasMore offset startId} timeSpans{start end tags{key value}}}}" % cur, token, )["timeSpans"] yield from data["timeSpans"] if not data["cursor"]["hasMore"]: return offset, start_id = data["cursor"]["offset"], data["cursor"]["startId"] def main(): by_mode = defaultdict(float) for span in spans(login()): tags = {t["key"]: t["value"] for t in span["tags"]} if tags.get("language") != "spanish": continue start = datetime.fromisoformat(span["start"]) end = ( datetime.fromisoformat(span["end"]) if span["end"] else datetime.now(timezone.utc) ) by_mode[tags.get("mode", "untagged")] += (end - start).total_seconds() / 3600 if "--by-mode" in sys.argv: for mode, hours in sorted(by_mode.items(), key=lambda kv: -kv[1]): print(f"{mode:12s} {hours:8.2f}") print(f"{sum(by_mode.values()):.2f}") if __name__ == "__main__": main()