initial commit
This commit is contained in:
commit
bb7123241d
3 changed files with 92 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ttracker.db
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
`ttracker` is a simple time tracker in python.
|
||||||
|
|
||||||
|
When launched, it checks if a time period is currently started. If not, it starts one and exits. If yes, it opens an editor, wait for a description of the past time period, stops it, and exits.
|
||||||
|
|
||||||
|
When it opens the editor, `ttracker` show the 10 last entries.
|
||||||
|
|
||||||
|
All time periods are stored in a sqlite database.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
`EDITOR=nano DATABASE=ttracker.db python3 ttracker.py`
|
80
ttracker.py
Executable file
80
ttracker.py
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import sys, tempfile, os
|
||||||
|
import sqlite3
|
||||||
|
from subprocess import call
|
||||||
|
|
||||||
|
EDITOR = os.environ.get('EDITOR', 'nano')
|
||||||
|
DATABASE = os.environ.get('TTRACKER_BD', 'ttracker.db')
|
||||||
|
|
||||||
|
def db_init(cur):
|
||||||
|
cur.execute("CREATE TABLE IF NOT EXISTS ttracker (start INTEGER, end INTEGER, text TEXT)")
|
||||||
|
|
||||||
|
def db_get_current_entry(cur):
|
||||||
|
res = cur.execute("SELECT * FROM ttracker ORDER BY start DESC").fetchone()
|
||||||
|
if res is not None and res[1] is None:
|
||||||
|
return res
|
||||||
|
return (None, None, None)
|
||||||
|
|
||||||
|
def new_entry(cur, now):
|
||||||
|
cur.execute(f'INSERT INTO ttracker VALUES (?, null, null)', (int(now.timestamp()),))
|
||||||
|
|
||||||
|
def end_entry(cur, entry, now):
|
||||||
|
entry_start = datetime.datetime.fromtimestamp(entry[0])
|
||||||
|
|
||||||
|
res = cur.execute("SELECT * FROM ttracker ORDER BY start DESC LIMIT 11").fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
initial_message = '\n\n' + \
|
||||||
|
f'# What did you do since {when_are_we(entry_start.date())} ({entry_start.strftime("%H:%M")})?\n' + \
|
||||||
|
"#\n"
|
||||||
|
|
||||||
|
for e in res:
|
||||||
|
if e[1] is not None:
|
||||||
|
start = datetime.datetime.fromtimestamp(e[0])
|
||||||
|
end = datetime.datetime.fromtimestamp(e[1])
|
||||||
|
initial_message += f'# {when_are_we(start.date())}, {start.strftime("%H:%M")}-{end.strftime("%H:%M")}: {e[2]}\n'
|
||||||
|
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
|
||||||
|
tf.write(initial_message.encode('utf_8'))
|
||||||
|
tf.flush()
|
||||||
|
call([EDITOR, tf.name])
|
||||||
|
|
||||||
|
tf.seek(0)
|
||||||
|
edited_message = [l.decode('utf_8') for l in tf.readlines()]
|
||||||
|
stripped_message = [l.strip() for l in edited_message if l.strip() and l != "" and l[0] != "#"]
|
||||||
|
if len(stripped_message) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
cur.execute('UPDATE ttracker SET end = ?, text = ? WHERE start = ?', (int(now.timestamp()), stripped_message[0], entry[0]))
|
||||||
|
print(f'Close entry ending at {now.strftime("%a %d %b")} - {now.strftime("%H:%M")}: {stripped_message[0]}')
|
||||||
|
|
||||||
|
|
||||||
|
def when_are_we(date):
|
||||||
|
delta = (datetime.date.today() - date).days
|
||||||
|
if delta == 0:
|
||||||
|
return "Today"
|
||||||
|
elif delta == 1:
|
||||||
|
return "Yesterday"
|
||||||
|
else:
|
||||||
|
return f'{delta} days ago'
|
||||||
|
|
||||||
|
def main():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
con = sqlite3.connect(DATABASE)
|
||||||
|
cur = con.cursor()
|
||||||
|
db_init(cur)
|
||||||
|
entry = db_get_current_entry(cur)
|
||||||
|
if entry[0] is None:
|
||||||
|
new_entry(cur, now)
|
||||||
|
print(f'Add new entry starting at {now.strftime("%a %d %b")} ({when_are_we(now.date())}) - {now.strftime("%H:%M")}')
|
||||||
|
else:
|
||||||
|
end_entry(cur, entry, now)
|
||||||
|
con.commit()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Reference in a new issue