Commit e1b6920c authored by Saswat's avatar Saswat

makefile; readme

parent 34711ae9
......@@ -2,7 +2,6 @@ build/
data/
pkgs/
dist/
venv/
atvenv/
src/__pycache/
src/__pycache__/
*.spec
......@@ -5,6 +5,7 @@ APP_NAME = "ActivityTracker"
VERSION = "1.0"
ARCH = "amd64"
PKG_NAME = "$(APP_NAME)_$(VERSION)_$(ARCH)"
INTERVAL = 300
PKGS_UTILS=\
scripts/activitytrackerd.service\
......@@ -24,24 +25,28 @@ GUI=\
src/plotter.py\
src/gui.py\
all: venv pkg
all: venv run
@echo Started Virtual Environment
@echo Built deb package in pkg/$(PKG_NAME).deb
venv: $(VENV)/bin/activate
@echo Virtual Environment is Set
# $(PYTHON) src/tracking_deamon.py &
# $(PYTHON) src/gui.py
$(VENV)/bin/activate: requirements.txt
@echo Creating Virtual Environment
python3 -m venv $(VENV)
$(PIP) install -r requirements.txt
pkg: dist/ActivityTracker dist/ActivityTrackerd $(PKGS_UTILS) appdata/config.json
run: daemon gui
daemon: $(DAEMON) $(UTILS)
$(PYTHON) src/trackingdaemon.py -d -i 10 &> log/deamon.log &
gui: $(GUI) $(UTILS)
$(PYTHON) src/gui.py -d &> deamon.log
pkg: dist/ActivityTracker dist/ActivityTrackerd $(PKGS_UTILS)
@echo Building Package
mkdir -p pkgs/$(PKG_NAME)/etc/$(APP_NAME)/
cp appdata/config.json pkgs/$(PKG_NAME)/etc/$(APP_NAME)/
mkdir -p pkgs/$(PKG_NAME)/DEBIAN/
cp scripts/control pkgs/$(PKG_NAME)/DEBIAN/
......@@ -65,6 +70,10 @@ dist/activitytrackerd: $(DAEMON) $(UTILS)
clean: clean-pkg clean-venv
@echo Clean completed
clean-run:
@echo cleaning previous run
rm log/*
clean-pkg:
@echo Cleaning Package related folders
rm -rf build
......
# Activity Tracker
### A utility to track your daily activities in the desktop.
#####Saswat Meher, Suraj Munjani
---
## Description
This program helps in keep track of which windows are being opened through it's daemon process activitytrackerd and provides a gui interface to visualise those activities through activitytracker.
For more details about the project please check the report file.
## How to run
Following are the instruction to run both the daemon and gui. First clone the repo into the local machine then proceed with the instructions.
We will make use of Makefile to run these programmes. Makefile internally make usage of debug mode in the programme and output redirection which is suitable for debugging purpose.
### Setting up a Virtual Environment
All the required libraries are mentioned in the `requirements.txt` file. You can be use Makefile to create a virtual env and install these dependencies.
```bash
make venv
```
This will will create a new virtual environment named `atvenv` and activate the same.
### Run daemon
The data about activities are collected using a daemon process. To start the daemon process make use of the make file.
```bash
make daemon
```
This will start a daemon process in the background that will start collecting user activity data dump it in the database file `data/activity_data.db`.
The interval at which the data is dumped into the disk can be also specified throught the makefile. E.g. to set interval to 10 Sec use command mentioned below.
```bash
make daemon interval=10
```
Data is dumped to the databse only after an event is detected after the interval of 10 sec.
Logs about the data being dumped into the database can be seen in `log/daemon.log`.
### Run GUI
The GUI utility to visualise the activity data can also be started using makefile.
```bash
make gui
```
Logs for the gui can be seen in `log/gui.log`.
### Packaging Instructions
This project can be packaged to generate a debian package os that it can be directly installed in a debian machine.
```bash
make pkgs
```
This command will generate binary executables independent of the python dependencies. It will use those binaries with various scripts needed for packaging to create a package structure.
Finally it will create a debian package inside pkg folder `pkg/ActivityTracker_1.0_amd64.deb` using dpkg-deb.
### Install the package
The above generated debian package can be installed using dpkg.
```bash
sudo dpkg -i <path_to_deb_package>
```
After installation the daemon should register itself as a systemd service and start automatically as a result of postinst script.
> **_NOTE:_** Currently after the installation the daemon is failing to start. So need to start `activitytrackerd` manually.
The GUI of program can be opened with the shell using the following command in shell.
```bash
activitytracker
```
### uninstall the program
The programme can be uninstalled using dpkg.
```bash
sudo dpkg -r activitytracker
```
{
"INTERVAL": 300,
"DATABASE_FILE": "/home/saswat/.ActivityTracker/activity_data.db"
}
\ No newline at end of file
Current deamon pid: 11802
Using DB file: data/activity_data.db
INSERT INTO activity VALUES (1669106240, '', 0)
INSERT INTO activity VALUES (1669106240, 'Visual Studio Code ', 6)
INSERT INTO activity VALUES (1669106240, 'Brave ', 1)
INSERT INTO activity VALUES (1669106240, 'Mozilla Firefox ', 3)
INSERT INTO activity VALUES (1669106250, 'Mozilla Firefox ', 5)
INSERT INTO activity VALUES (1669106250, 'Visual Studio Code ', 5)
INSERT INTO activity VALUES (1669106260, 'Visual Studio Code ', 9)
INSERT INTO activity VALUES (1669106260, 'Mozilla Firefox ', 1)
INSERT INTO activity VALUES (1669106270, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106280, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106290, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106300, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106310, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106320, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106330, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106340, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106350, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106360, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106370, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106380, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106390, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106400, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106410, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106420, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106430, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106440, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106450, 'Visual Studio Code ', 10)
X protocol error:
<class 'Xlib.error.BadWindow'>: code = 3, resource_id = <class 'Xlib.xobject.resource.Resource'>(0x05800027), sequence_number = 120, major_opcode = 2, minor_opcode = 0
INSERT INTO activity VALUES (1669106460, 'Visual Studio Code ', 2)
INSERT INTO activity VALUES (1669106460, 'Activity Tracker ', 8)
INSERT INTO activity VALUES (1669106470, 'Activity Tracker ', 10)
INSERT INTO activity VALUES (1669106480, 'Activity Tracker ', 8)
INSERT INTO activity VALUES (1669106480, 'Visual Studio Code ', 2)
INSERT INTO activity VALUES (1669106490, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106500, 'Visual Studio Code ', 1)
INSERT INTO activity VALUES (1669106500, 'Mozilla Firefox ', 9)
INSERT INTO activity VALUES (1669106510, 'Mozilla Firefox ', 9)
INSERT INTO activity VALUES (1669106510, 'Visual Studio Code ', 1)
INSERT INTO activity VALUES (1669106520, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106530, 'Visual Studio Code ', 8)
INSERT INTO activity VALUES (1669106530, 'Mozilla Firefox ', 2)
INSERT INTO activity VALUES (1669106540, 'Mozilla Firefox ', 8)
INSERT INTO activity VALUES (1669106540, 'Visual Studio Code ', 2)
INSERT INTO activity VALUES (1669106550, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106560, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106570, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106580, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106590, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106600, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106610, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106620, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106630, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106640, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106650, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106660, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106670, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106680, 'Visual Studio Code ', 3)
INSERT INTO activity VALUES (1669106680, 'Mozilla Firefox ', 7)
INSERT INTO activity VALUES (1669106690, 'Mozilla Firefox ', 10)
INSERT INTO activity VALUES (1669106700, 'Mozilla Firefox ', 10)
INSERT INTO activity VALUES (1669106710, 'Mozilla Firefox ', 10)
INSERT INTO activity VALUES (1669106720, 'Mozilla Firefox ', 10)
INSERT INTO activity VALUES (1669106730, 'Mozilla Firefox ', 8)
INSERT INTO activity VALUES (1669106730, 'Brave ', 1)
INSERT INTO activity VALUES (1669106730, '', 1)
INSERT INTO activity VALUES (1669106740, '', 2)
INSERT INTO activity VALUES (1669106740, 'Visual Studio Code ', 8)
INSERT INTO activity VALUES (1669106750, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106760, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106770, 'Visual Studio Code ', 10)
INSERT INTO activity VALUES (1669106780, 'Visual Studio Code ', 10)
Using DB file: data/activity_data.db
2022-11-22 1 hr 53 min
2022-11-21 3 hr 29 min
2022-11-20 6 hr 41 min
2022-11-19 0 hr 10 min
2022-11-20 6 hr 41 min
2022-11-21 3 hr 29 min
2022-11-22 1 hr 54 min
sudo systemctl daemon-reload
sudo systemctl stop activitytrackerd.service
sudo systemctl disable activitytrackerd.service
sudo systemctl enable activitytrackerd.service
sudo systemctl start activitytrackerd.service
sudo systemctl status activitytrackerd.service
import sqlite3
from datetime import datetime, timedelta
import os
import sys
class DBHandler:
"""
......@@ -49,6 +49,7 @@ class DBHandler:
cursor = self.conn.execute("SELECT * from ACTIVITY ")
for row in cursor:
print(row)
sys.stdout.flush()
return
def write_interval(self, interval_start, app_name, duration):
......@@ -56,7 +57,8 @@ class DBHandler:
Write an entry for the amount of time an application was active in an interval.
"""
query = f"INSERT INTO activity VALUES ({interval_start}, '{app_name}', {duration})"
#print(query)
print(query)
sys.stdout.flush()
self.conn.execute(query)
self.conn.commit()
......@@ -65,7 +67,7 @@ class DBHandler:
Provided a date instance return all data present corresponding the whole week
for the date.
"""
print(date)
sys.stdout.flush()
date = datetime(date.year, date.month, date.day, 0, 0, 0)
start = date - timedelta(days=date.weekday())
end = start + timedelta(days=7)
......
......@@ -5,15 +5,19 @@ import plotter
from datetime import datetime, timedelta
from tkinter.ttk import *
from tkcalendar import DateEntry
import sys
import getopt
DEBUG = False
class ActivityTracker:
"""
This class stores all the variables needed for the gui.
Also updates graphs and details when the date is changed.
"""
def __init__(self) -> None:
def __init__(self, debug) -> None:
self.root = Tk() # A tikinter object to create the root of the window
self.plotter = plotter.ActivityPlotter()
self.plotter = plotter.ActivityPlotter(debug)
self.root.title('Activity Tracker')
width = self.root.winfo_screenwidth()
......@@ -135,9 +139,35 @@ class ActivityTracker:
self.__refresh_app()
return
Usage = """
Usage: <executable> [-h|-d]
-h | --help : help
-d | --debug : Run application in debug mode
"""
def parse_cmdargs():
global DEBUG
argv = sys.argv[1:]
short_opts = "hd"
long_opts = ["help", "debug"]
try:
args, _ = getopt.getopt(argv, short_opts, long_opts)
for opt, arg in args:
if opt in ["-h", "--help"]:
print(Usage)
elif opt in["-d", "--debug"]:
DEBUG = True
except getopt.error as err:
print (str(err))
print(Usage)
exit(1)
if __name__ == '__main__':
"""
Execution starts from here, Creating a ActivityTracker object, then it is set on mainloop().
"""
tracker = ActivityTracker()
parse_cmdargs()
tracker = ActivityTracker(DEBUG)
tracker.root.mainloop()
\ No newline at end of file
......@@ -9,14 +9,13 @@ class ActivityPlotter:
"""
Class to help plotting grpahs in GUI.
"""
def __init__(self) -> None:
def __init__(self, debug:False) -> None:
"""
Init database handler and various constant variables
"""
config = utils.load_config()
db_path = utils.get_db_path(debug)
plt.rcParams.update({'font.size': 16})
self.db = dbhandler.DBHandler(config['DATABASE_FILE'])
print(config['DATABASE_FILE'])
self.db = dbhandler.DBHandler(db_path)
self.week_days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
self.hours = ['12am', '3am', '6am', '9am', '12pm', '3pm', '6pm', '9pm', '12am']
......@@ -97,7 +96,6 @@ class ActivityPlotter:
curr_date_time = self.perday[week_day]
screen_time_text = str(int(curr_date_time/3600)) + " hr " + str(int((curr_date_time%3600)/60)) + " min"
print(screen_time_text)
return figure, screen_time_text
def __get_day_plot(self):
......@@ -149,5 +147,5 @@ class ActivityPlotter:
week_fig, screen_time_text = self.__get_week_plot()
day_fig = self.__get_day_plot()
app_fig = self.__get_app_plot()
print(self.curr_date, screen_time_text)
return week_fig, day_fig, app_fig, screen_time_text
from contextlib import contextmanager
from typing import Any, Dict, Optional, Tuple, Union
from Xlib import X
from Xlib.display import Display
from Xlib.error import XError
......@@ -10,11 +8,21 @@ from Xlib.xobject.drawable import Window
import os
import signal
import sys
import getopt
import eventhandler
import utils
event_handler = None
DEBUG = False
INTERVAL = 300
Usage ="""
Usage: <executable> [-h|-d|-i:]
-h | --help : help
-d | --debug : Run application in debug mode
-i | --interval: Interval to dump data to the disk
"""
@contextmanager
def create_window_obj(disp, window_id):
......@@ -159,21 +167,43 @@ def init_eventhandler():
Initialise the EventHandler to handle a change in the name of the window
"""
global event_handler
config = utils.load_config()
event_handler = eventhandler.EventHandler(config["INTERVAL"], config["DATABASE_FILE"])
db_file = utils.get_db_path(DEBUG)
event_handler = eventhandler.EventHandler(INTERVAL, db_file)
return event_handler
def parse_cmdargs():
global DEBUG
global INTERVAL
argv = sys.argv[1:]
short_opts = "hdi:"
long_opts = ["help", "debug", "interval="]
try:
args, _ = getopt.getopt(argv, short_opts, long_opts)
for opt, arg in args:
if opt in ["-h", "--help"]:
print(Usage)
elif opt in["-d", "--debug"]:
DEBUG = True
elif opt in ["-i", "--interval"]:
INTERVAL = int(arg)
except getopt.error as err:
print (str(err))
print(Usage)
exit(1)
if __name__ == '__main__':
"""
Main method that starts the process that starts detecting changes in the active window using EventFetcher.
Handle any changes using EventHandler class.
"""
parse_cmdargs()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
print("Current deamon pid:", os.getpid())
sys.stdout.flush()
event_handler = init_eventhandler()
event_fetcher = EventFetcher()
......
from curses.ascii import isalnum
import json
import os
import os, sys
def extract_app_name(title):
"""
......@@ -18,29 +17,21 @@ def extract_app_name(title):
i -= 1
return app_name
def load_config():
"""
Load the config file. This contains the interval time, Location for database, etc.
"""
local_file = "../appdata/config.json"
global_file = "/etc/ActivityTracker/config.json"
if os.path.exists(global_file):
f = open(global_file)
config = json.load(f)
f.close()
print("Using global config")
elif os.path.exists(local_file):
f = open(local_file)
config = json.load(f)
f.close()
print("Using dev config")
def get_db_path(debug):
DEV_DB_PATH = "data/activity_data.db"
user_path = os.path.expanduser('~')
DB_PATH = user_path+"/.activitytracker/activity_data.db"
if debug:
if os.path.exists(os.path.dirname(DEV_DB_PATH)) == False:
os.mkdir(os.path.dirname(DEV_DB_PATH))
print("Using DB file: ", DEV_DB_PATH)
sys.stdout.flush()
return DEV_DB_PATH
else:
config = dict()
config['INTERVAL'] = 300
deafult_db_file_folder = os.path.expanduser('~') + "/.ActivityTracker/"
if os.path.exists(deafult_db_file_folder) == False:
os.mkdir(deafult_db_file_folder)
config['DATABASE_FILE'] = deafult_db_file_folder + "activity_data.db"
print("Using default config")
print(config)
return config
if os.path.exists(os.path.dirname(DB_PATH)) == False:
os.mkdir(os.path.dirname(DB_PATH))
print("Using DB file: ", DB_PATH)
sys.stdout.flush()
return DB_PATH
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment