commit 0835fef493d20f7cad23ef6d064861aed1548d6e Author: Dima Gerasimov Date: Thu May 31 21:05:56 2018 +0100 Initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07d89cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,170 @@ + +# Created by https://www.gitignore.io/api/python,emacs + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile +projectile-bookmarks.eld + +# directory configuration +.dir-locals.el + +# saveplace +places + +# url cache +url/cache/ + +# cedet +ede-projects.el + +# smex +smex-items + +# company-statistics +company-statistics-cache.el + +# anaconda-mode +anaconda-mode/ + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + + +# End of https://www.gitignore.io/api/python,emacs diff --git a/rescuetime/__init__.py b/rescuetime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rescuetime/__main__.py b/rescuetime/__main__.py new file mode 100644 index 0000000..28d32c0 --- /dev/null +++ b/rescuetime/__main__.py @@ -0,0 +1,102 @@ +import logging +from os import listdir +from os.path import join + +from kython import json_load, JSONType +from kython.logging import setup_logzero + +logger = logging.getLogger("rescuetime-provider") +setup_logzero(logger) + + +PATH = "/L/backups/rescuetime" + +def try_load(fp: str): + try: + j: JSONType + with open(fp, 'r') as fo: + j = json_load(fo) + + if j is None: + logger.warning(f"Corrupted: {fp}") + return None + + return j + except Exception as e: + if 'Expecting value' in str(e): + logger.warning(f"Corrupted: {fp}") + else: + raise e + return None + +from datetime import datetime, timedelta +from typing import NamedTuple, Dict, List + +_DT_FMT = "%Y-%m-%dT%H:%M:%S" + +class Entry(NamedTuple): + dt: datetime # TODO mm, no timezone? + duration_s: int + + @staticmethod + def from_dict(row: Dict): + dt_s = row['Date'] + dur = row['Time Spent (seconds)'] + dt = datetime.strptime(dt_s, _DT_FMT) + return Entry(dt=dt, duration_s=dur) + + @staticmethod + def from_row(row: List): + COL_DT = 0 + COL_DUR = 1 + dt_s = row[COL_DT] + dur = row[COL_DUR] + dt = datetime.strptime(dt_s, _DT_FMT) + return Entry(dt=dt, duration_s=dur) + +from typing import Set +all_entries: Set[Entry] = set() + +for f in sorted(listdir(PATH))[-5:]: # TODO FIXME + fp = join(PATH, f) + j = try_load(fp) + if j is None: + continue + + cols = j['row_headers'] + seen = 0 + total = 0 + for row in j['rows']: + e = Entry.from_row(row) + total += 1 + if e in all_entries: + seen += 1 + else: + all_entries.add(e) + print(f"{f}: {seen}/{total}") + # import ipdb; ipdb.set_trace() + # print(len(j)) + +all_sorted = sorted(all_entries, key=lambda e: e.dt) +gap = timedelta(hours=3) + +groups = [] +group = [] + +for e in all_sorted: + if len(group) > 0 and e.dt - group[-1].dt > gap: + groups.append(group) + group = [] + group.append(e) + +if len(group) > 0: + groups.append(group) + group = [] + +for gr in groups: + print(f"{gr[0].dt}--{gr[-1].dt}") + + +# TODO merged db? +# TODO ok, it summarises my sleep intervals pretty well. I guess should adjust it for the fact I don't sleep during the day, and it would be ok! + diff --git a/run b/run new file mode 100755 index 0000000..0d0e25d --- /dev/null +++ b/run @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" +python3 -m rescuetime \ No newline at end of file