├── README └── trackmac.py /README: -------------------------------------------------------------------------------- 1 | # A simple time tracker for Mac OS X by Nat Friedman (nat@nat.org). 2 | # 3 | # Written May 6, 2010 in Munich, while a soft rain fell. 4 | # 5 | # Run this script in a terminal. It displays activity statistics 6 | # from the last 24 hours, like this: 7 | # 8 | # 1h 8m57s 70% Google Chrome 9 | # 14m17s 14% Mail 10 | # 8m11s 8% iChat 11 | # 3m16s 3% Colloquy 12 | # 1m28s 1% 1Password 13 | # 43s 0% Terminal 14 | # 12s 0% TextMate 15 | # 4s 0% Finder 16 | # 4s 0% SecurityAgent 17 | # 18 | # 1h37m12s Sitting at the computer 19 | # 3h37m16s Doing something else 20 | # 5h14m28s Total 21 | # 22 | # It detects idle time based on the screensaver, so lower your 23 | # screensaver delay or use a hot corner to improve accuracy. 24 | # 25 | # It doesn't save the data, so if you kill the script it loses the 26 | # history. 27 | -------------------------------------------------------------------------------- /trackmac.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # trackmac.py 4 | # 5 | # A simple time tracker for Mac OS X by Nat Friedman (nat@nat.org). 6 | # 7 | # Written May 6, 2010 in Munich, while a soft rain fell. 8 | # 9 | # Run this script in a terminal. It displays activity statistics 10 | # from the last 24 hours, like this: 11 | # 12 | # 1h 8m57s 70% Google Chrome 13 | # 14m17s 14% Mail 14 | # 8m11s 8% iChat 15 | # 3m16s 3% Colloquy 16 | # 1m28s 1% 1Password 17 | # 43s 0% Terminal 18 | # 12s 0% TextMate 19 | # 4s 0% Finder 20 | # 4s 0% SecurityAgent 21 | # 22 | # 1h37m12s Sitting at the computer 23 | # 3h37m16s Doing something else 24 | # 5h14m28s Total 25 | # 26 | # It detects idle time based on the screensaver, so lower your 27 | # screensaver delay to improve accuracy. 28 | # 29 | # It doesn't save the data, so if you kill the script it loses the 30 | # history. You might want to kill it every day or so, so it doesn't 31 | # get too big (it keeps all the old samples around). 32 | 33 | import time, math, sys 34 | from AppKit import NSWorkspace 35 | from operator import itemgetter 36 | 37 | # Sample every second 38 | sample_interval = 1 39 | idle_activities = ["loginwindow", "ScreenSaverEngine"] 40 | 41 | def friendly_duration(secs): 42 | minutes, seconds = divmod(secs, 60) 43 | hours, minutes = divmod(minutes, 60) 44 | duration = [] 45 | if hours > 0: 46 | duration.append('%2dh' % hours) 47 | else: 48 | duration.append(' ') 49 | 50 | if minutes > 0: 51 | duration.append('%2dm' % minutes) 52 | else: 53 | duration.append(' ') 54 | 55 | if seconds > 0: 56 | duration.append('%2ds' % seconds) 57 | else: 58 | duration.append(' ') 59 | 60 | return ''.join(duration) 61 | 62 | def gather_activities(samples): 63 | # Skip past all samples older than 24 hours 64 | now = time.time() 65 | for i in range(len(samples) - 1, 0, -1): 66 | if (now - samples[i][0]) < 24 * 60 * 60: 67 | first_i = i 68 | 69 | total_time = samples[len(samples) - 1][0] - samples[first_i][0] 70 | 71 | # Count up all the activities 72 | activities = {} 73 | for i in range(first_i + 1, len(samples)): 74 | activity = samples[i - 1][1] 75 | duration = samples[i][0] - samples[i - 1][0] 76 | 77 | # If the screen was locked or the computer was suspended 78 | # (or the script was not running), count that as idle time. 79 | if activity in idle_activities or duration > (sample_interval + 3): 80 | activity = "idle" 81 | 82 | if activity in activities: 83 | activities[activity] += duration 84 | else: 85 | activities[activity] = duration 86 | 87 | return activities, total_time 88 | 89 | def print_summary(samples): 90 | sys.stdout.write("\033[2J\033[H") 91 | if len(samples) < 3: 92 | print "Please wait, gathering data..." 93 | return 94 | 95 | activities, total_time = gather_activities(samples) 96 | 97 | sorted_activities = sorted(activities.items(), key=itemgetter(1)) 98 | sorted_activities.reverse() 99 | 100 | if "idle" in activities: 101 | idle_time = activities["idle"] 102 | else: 103 | idle_time = 0 104 | keyboard_time = total_time - idle_time 105 | 106 | for a in sorted_activities: 107 | if a[0] != "idle": 108 | print friendly_duration(a[1]) + " " + ('%3d' % (a[1] * 100 / keyboard_time)) + "% " + a[0] 109 | 110 | print 111 | print friendly_duration(keyboard_time) + " Sitting at the computer" 112 | if (idle_time > 0): 113 | print friendly_duration(idle_time) + " Doing something else" 114 | print friendly_duration(total_time) + " Total" 115 | 116 | def run_profiler(): 117 | samples = [] 118 | while True: 119 | activeAppName = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationName'] 120 | samples.append([int(time.time()), activeAppName]) 121 | print_summary(samples) 122 | time.sleep(sample_interval) 123 | 124 | run_profiler() --------------------------------------------------------------------------------