-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimetracker.py
286 lines (248 loc) · 9.3 KB
/
timetracker.py
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import ctypes
import time
import datetime
import psutil
import getpass
import mysql.connector
import json
import csv
import os
import tkinter as tk
from tkinter import StringVar
from pynput import mouse, keyboard
# Load MySQL database credentials from config file
with open('db_config.json') as config_file:
db_config = json.load(config_file)
# File path for the CSV
csv_file_path = 'timetracker_log.csv'
# Function to get the active window title and process ID
def get_active_window_details():
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
pid = ctypes.c_ulong()
hwnd = user32.GetForegroundWindow()
user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
process_id = pid.value
length = user32.GetWindowTextLengthW(hwnd)
buf = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buf, length + 1)
return buf.value, process_id
# Function to format time span
def format_time_span(seconds):
span = datetime.timedelta(seconds=seconds)
return str(span)
# Function to connect to MySQL database
def connect_to_database():
return mysql.connector.connect(
host=db_config['host'],
user=db_config['user'],
password=db_config['password'],
database=db_config['database'],
port=db_config.get('port', 3306) # Use port from config or default to 3306
)
# Function to create the table and add missing columns if they do not exist
def create_table_if_not_exists(cursor):
# Create the table if it doesn't exist
create_table_query = '''
CREATE TABLE IF NOT EXISTS cg_timetracker (
ID INT AUTO_INCREMENT PRIMARY KEY,
Time_Started DATETIME,
Duration VARCHAR(255),
Seconds INT,
Time_Ended DATETIME,
Application_Name VARCHAR(255),
Window_Name VARCHAR(255),
Project_Name VARCHAR(255),
Client VARCHAR(255),
Tags VARCHAR(255),
Current_User_Name VARCHAR(255)
)
'''
cursor.execute(create_table_query)
# Add the 'Seconds' column if it does not exist
try:
cursor.execute('''
ALTER TABLE cg_timetracker ADD COLUMN Seconds INT
''')
except mysql.connector.Error as err:
if err.errno == 1060: # Column already exists
pass
else:
print(f"Error adding column: {err}")
# Function to insert data into MySQL table
def insert_into_database(cursor, log_entry):
insert_query = '''
INSERT INTO cg_timetracker (
Time_Started, Duration, Seconds, Time_Ended, Application_Name, Window_Name,
Project_Name, Client, Tags, Current_User_Name
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
'''
cursor.execute(insert_query, (
log_entry["Time Started"],
log_entry["Duration"],
log_entry["Seconds"],
log_entry["Time Ended"],
log_entry["Application Name"],
log_entry["Window Name"],
log_entry["Project Name"],
log_entry["Client"],
log_entry["Tags"],
log_entry["Current User"]
))
# Function to write data to CSV file
def write_to_csv(log_entry):
file_exists = os.path.isfile(csv_file_path)
with open(csv_file_path, mode='a', newline='') as file:
writer = csv.writer(file)
if not file_exists:
writer.writerow([
"Time Started", "Duration", "Seconds", "Time Ended", "Application Name", "Window Name",
"Project Name", "Client", "Tags", "Current User"
])
writer.writerow([
log_entry["Time Started"],
log_entry["Duration"],
log_entry["Seconds"],
log_entry["Time Ended"],
log_entry["Application Name"],
log_entry["Window Name"],
log_entry["Project Name"],
log_entry["Client"],
log_entry["Tags"],
log_entry["Current User"]
])
# Function to handle user activity
def on_move(x, y):
global last_activity_time
last_activity_time = datetime.datetime.now()
def on_click(x, y, button, pressed):
global last_activity_time
last_activity_time = datetime.datetime.now()
def on_press(key):
global last_activity_time
last_activity_time = datetime.datetime.now()
# Set up listeners for mouse and keyboard activity
mouse_listener = mouse.Listener(on_move=on_move, on_click=on_click)
keyboard_listener = keyboard.Listener(on_press=on_press)
mouse_listener.start()
keyboard_listener.start()
# Initialize tracking variables
start_time = datetime.datetime.now()
last_activity_time = start_time
is_active = True
paused = False
last_window_title = ""
last_process_id = 0
# Idle tracking variables
idle_start_time = None
logging_idle = False
# Get the current user's name
current_user = getpass.getuser()
# GUI setup
class TimeTrackerApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Time Tracker")
self.geometry("300x100")
self.window_name_var = StringVar()
self.duration_var = StringVar()
self.create_widgets()
def create_widgets(self):
tk.Label(self, text="Active Window:").pack(pady=5)
tk.Label(self, textvariable=self.window_name_var).pack(pady=5)
tk.Label(self, text="Duration:").pack(pady=5)
tk.Label(self, textvariable=self.duration_var).pack(pady=5)
def update_window_info(self, window_name, duration):
self.window_name_var.set(window_name)
self.duration_var.set(duration)
app = TimeTrackerApp()
# Main loop to track active window and update GUI
while is_active:
if not paused:
active_window_title, process_id = get_active_window_details()
current_time = datetime.datetime.now()
if active_window_title != last_window_title or process_id != last_process_id:
duration = (current_time - start_time).total_seconds()
start_time = current_time
# Prepare data for logging
try:
process = psutil.Process(process_id)
application_name = process.name()
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
application_name = "Unknown"
log_entry = {
"Time Started": current_time.strftime("%Y/%m/%d %H:%M:%S"),
"Duration": format_time_span(duration),
"Seconds": duration,
"Time Ended": current_time.strftime("%Y/%m/%d %H:%M:%S"),
"Application Name": application_name,
"Window Name": active_window_title if active_window_title else "Unknown",
"Project Name": "", # Default project_name
"Client": "", # Default Client
"Tags": "", # Default Tags
"Current User": current_user
}
# Update last known window details
last_window_title = active_window_title
last_process_id = process_id
# Save data to MySQL and CSV
try:
db = connect_to_database()
cursor = db.cursor()
create_table_if_not_exists(cursor)
insert_into_database(cursor, log_entry)
db.commit()
cursor.close()
db.close()
except mysql.connector.Error as err:
print(f"Error: {err}")
# Always attempt to write to CSV
try:
write_to_csv(log_entry)
except Exception as e:
print(f"CSV Write Error: {e}")
# Update GUI
app.update_window_info(active_window_title, format_time_span(duration))
app.update()
last_activity_time = current_time
# Check for user idle time
idle_time = (current_time - last_activity_time).total_seconds()
if idle_time > 10:
if not logging_idle:
idle_start_time = current_time
logging_idle = True
else:
if logging_idle:
duration = (current_time - idle_start_time).total_seconds()
# Log idle time
log_entry = {
"Time Started": idle_start_time.strftime("%Y/%m/%d %H:%M:%S"),
"Duration": format_time_span(duration),
"Seconds": duration,
"Time Ended": current_time.strftime("%Y/%m/%d %H:%M:%S"),
"Application Name": "Unknown",
"Window Name": "Idle",
"Project Name": "idle",
"Client": "",
"Tags": "idle",
"Current User": current_user
}
# Save idle data to MySQL and CSV
try:
db = connect_to_database()
cursor = db.cursor()
create_table_if_not_exists(cursor)
insert_into_database(cursor, log_entry)
db.commit()
cursor.close()
db.close()
except mysql.connector.Error as err:
print(f"Error: {err}")
try:
write_to_csv(log_entry)
except Exception as e:
print(f"CSV Write Error: {e}")
logging_idle = False
# Check every 1 second
time.sleep(1)
app.mainloop()