-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtracker-linux.py
More file actions
102 lines (92 loc) · 3.28 KB
/
tracker-linux.py
File metadata and controls
102 lines (92 loc) · 3.28 KB
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
import time
import base64
import urllib.request
import urllib.error
import json
import psutil
from datetime import datetime
import pyautogui
import subprocess
WAKATIME_API_KEY = 'YOUR_WAKATIME_API_KEY'
HEARTBEAT_INTERVAL = 120
CHECK_INTERVAL = 30
APPS = [
"""
Insert code block from /apps here
{
"process_name": "",
"window_keyword": "",
"project": "",
"language": "",
"plugin": "general-wakatime"
},
"""
]
def is_process_running(name):
for proc in psutil.process_iter(['name']):
if name.lower() in (proc.info['name'] or "").lower():
return True
return False
def get_active_window_title():
try:
win_id = subprocess.check_output(["xdotool", "getactivewindow"]).decode().strip()
win_name = subprocess.check_output(["xdotool", "getwindowname", win_id]).decode().strip()
return win_name
except:
pass
return None
def user_is_active(window_title=None, threshold_seconds=CHECK_INTERVAL):
pos1 = pyautogui.position()
time.sleep(threshold_seconds)
pos2 = pyautogui.position()
return pos1 != pos2 and get_active_window_title() == window_title
def save_heartbeat_local(payload):
with open("heartbeats.json", "a", encoding='utf-8') as f:
json.dump(payload, f)
f.write("\n")
def send_heartbeat(entity, app_config):
encoded_key = base64.b64encode(WAKATIME_API_KEY.encode()).decode()
headers = {
"Authorization": f"Basic {encoded_key}",
"Content-Type": "application/json"
}
payload = {
"time": datetime.utcnow().timestamp(),
"entity": entity,
"type": "app",
"category": "coding",
"is_write": False,
"project": app_config['project'],
"language": app_config['language'],
"plugin": app_config['plugin']
}
req = urllib.request.Request(
url='https://hackatime.hackclub.com/api/hackatime/v1/users/current/heartbeats',
data=json.dumps(payload).encode('utf-8'),
headers=headers,
method='POST'
)
try:
with urllib.request.urlopen(req) as response:
print(f"[{datetime.now()}] Heartbeat: {entity} -> {app_config['project']} ({response.status})")
save_heartbeat_local(payload)
except urllib.error.HTTPError as e:
print(f"[{datetime.now()}] HTTP error: {e.code} - {e.reason}")
except urllib.error.URLError as e:
print(f"[{datetime.now()}] Network error: {e.reason}")
def main():
last_sent = {app['process_name']: 0 for app in APPS}
last_window = {app['process_name']: "" for app in APPS}
while True:
now = time.time()
current_title = get_active_window_title()
for app in APPS:
if is_process_running(app['process_name']):
if current_title and app['window_keyword'].lower() in current_title.lower():
if user_is_active(window_title=current_title):
if now - last_sent[app['process_name']] > HEARTBEAT_INTERVAL or current_title != last_window[app['process_name']]:
send_heartbeat(current_title, app)
last_sent[app['process_name']] = now
last_window[app['process_name']] = current_title
if __name__ == "__main__":
main()