From 93c9647b3b37e48761c65040634da93be9af6b58 Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Tue, 30 Sep 2014 23:30:36 +0530 Subject: [PATCH 1/8] Adds basic analytics framework (mixpanel) - Tracking launch event, with arguments passed --- hackertray/__init__.py | 12 ++++++++++++ hackertray/analytics.py | 20 ++++++++++++++++++++ setup.py | 1 + 3 files changed, 33 insertions(+) create mode 100644 hackertray/analytics.py diff --git a/hackertray/__init__.py b/hackertray/__init__.py index 5be0862..bbbd945 100644 --- a/hackertray/__init__.py +++ b/hackertray/__init__.py @@ -26,11 +26,13 @@ import signal from hackernews import HackerNews from chrome import Chrome from version import Version +from analytics import Analytics class HackerNewsApp: HN_URL_PREFIX = "https://news.ycombinator.com/item?id=" UPDATE_URL = "https://github.com/captn3m0/hackertray#upgrade" ABOUT_URL = "https://github.com/captn3m0/hackertray" + MIXPANEL_TOKEN = "51a04e37dad59393c7371407e84a8050" def __init__(self, args): #Load the database home = expanduser("~") @@ -42,6 +44,9 @@ class HackerNewsApp: except ValueError: self.db = set() + # Setup analytics + Analytics.setup(args.dnt, HackerNewsApp.MIXPANEL_TOKEN) + # create an indicator applet self.ind = appindicator.Indicator("Hacker Tray", "hacker-tray", appindicator.CATEGORY_APPLICATION_STATUS) self.ind.set_status(appindicator.STATUS_ACTIVE) @@ -91,6 +96,11 @@ class HackerNewsApp: self.ind.set_menu(self.menu) self.refresh(chrome_data_directory=args.chrome) + # Now that we're all done with the boot, send a beacone home + launch_data = vars(args) + launch_data['version'] = Version.current() + Analytics.track('launch', launch_data) + def toggleComments(self, widget): """Whether comments page is opened or not""" self.commentState = not self.commentState @@ -195,7 +205,9 @@ def main(): parser.add_argument('-v','--version', action='version', version=Version.current()) parser.add_argument('-c','--comments', dest='comments',action='store_true', help="Load the HN comments link for the article as well") parser.add_argument('--chrome', dest='chrome', help="Specify a Google Chrome Profile directory to use for matching chrome history") + parser.add_argument('--dnt', dest='dnt',action='store_true', help="Disable all analytics (Do Not Track)") parser.set_defaults(comments=False) + parser.set_defaults(dnt=False) args = parser.parse_args() indicator = HackerNewsApp(args) indicator.run() diff --git a/hackertray/analytics.py b/hackertray/analytics.py new file mode 100644 index 0000000..e7b453a --- /dev/null +++ b/hackertray/analytics.py @@ -0,0 +1,20 @@ +from mixpanel import Mixpanel + +class Analytics: + # Setup analytics. + # dnt - do not track. Disables tracking if True + # token - The mixpanel token + @staticmethod + def setup(dnt, token): + Analytics.dnt = dnt + Analytics.tracker = Mixpanel(token) + if(dnt == True): + print "[+] Analytics disabled" + # Track an event + # event - string containing the event name + # data - data related to the event, defaults to {} + @staticmethod + def track(event, data = {}): + if(Analytics.dnt == False): + # All events are tracked anonymously + Analytics.tracker.track("anonymous", event, data) \ No newline at end of file diff --git a/setup.py b/setup.py index bf68850..01430fa 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ setup(name='hackertray', }, install_requires=[ 'requests>=2.2.1', + 'mixpanel-py>=3.0.0' ], entry_points={ 'console_scripts': ['hackertray = hackertray:main'], From 6c93751d7346e85614741995c4e08bf9a47e72d1 Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 00:14:23 +0530 Subject: [PATCH 2/8] Fixes travis build by installing mixpanel --- .travis.yml | 1 + hackertray/__init__.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 67faca2..c8cb0aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ python: install: - pip install requests - pip install nose + - pip install mixpanel-py # command to run tests, e.g. python setup.py test script: nosetests --nocapture notifications: diff --git a/hackertray/__init__.py b/hackertray/__init__.py index bbbd945..e750729 100644 --- a/hackertray/__init__.py +++ b/hackertray/__init__.py @@ -95,6 +95,7 @@ class HackerNewsApp: self.ind.set_menu(self.menu) self.refresh(chrome_data_directory=args.chrome) + self.launch_analytics(args) # Now that we're all done with the boot, send a beacone home launch_data = vars(args) From 11c02ba898e1f850742b926b7fb365a59de7ed7f Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 00:38:25 +0530 Subject: [PATCH 3/8] Adds browser and platform info to analytics --- hackertray/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hackertray/__init__.py b/hackertray/__init__.py index e750729..d4ccd3b 100644 --- a/hackertray/__init__.py +++ b/hackertray/__init__.py @@ -2,6 +2,8 @@ import os import requests +import platform +import subprocess if(os.environ.get('TRAVIS')!='true'): import pygtk @@ -97,9 +99,15 @@ class HackerNewsApp: self.refresh(chrome_data_directory=args.chrome) self.launch_analytics(args) + def launch_analytics(self, args): # Now that we're all done with the boot, send a beacone home launch_data = vars(args) launch_data['version'] = Version.current() + launch_data['platform'] = platform.linux_distribution() + try: + launch_data['browser'] = subprocess.check_output(["xdg-settings","get","default-web-browser"]).strip() + except subprocess.CalledProcessError as e: + launch_data['browser'] = "unknown" Analytics.track('launch', launch_data) def toggleComments(self, widget): From 5a73dd9d9336f1a9be48ec80442bcd4c782191eb Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 06:40:05 +0530 Subject: [PATCH 4/8] Adds analytics note to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f9e0133..0a87338 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,9 @@ To develop on hackertray, or to test out experimental versions, do the following - Run `(sudo) python setup.py develop` in the hackertray root directory - Run `hackertray` with the required command line options from anywhere. +##Analytics +TO help improve the project and learn how its being used, I've added Analytics in hackertray. The `--dnt` switch disables all analytics so that you can opt-out if desired. All data is collected anonymously, with no machine id or user-identifying information being sent back. To learn more, and see which events are being tracked, see the [Analytics](wiki/Analytics) wiki page. + ##Credits - Mark Rickert for [Hacker Bar](http://hackerbarapp.com/). From 96a2364c04ec85c2168d1c489931dcc49e4c9b97 Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 06:51:29 +0530 Subject: [PATCH 5/8] Adds information about --dnt switch --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a87338..35b67df 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ HackerTray accepts its various options via the command line. Run `hackertray -h` 1. `-c`: Enables comments support. Clicking on links will also open the comments page on HN. Can be switched off via the UI, but the setting is not remembered. 2. `--chrome PROFILE_PATH`: Specifying a profile path to a chrome directory will make HackerTray read the Chrome History file to mark links as read. Links are checked once every 5 minutes, which is when the History file is copied (to override the lock in case Chrome is open), searched using sqlite and deleted. This feature is still experimental. +3. `--dnt`: Disable analytics. Hackertray will no longer collect any sort of analytics. I'd prefer it if you left out this switch, as it helps me improve hackertray by understanding how its being used. ###Google Chrome Profile Path @@ -91,7 +92,7 @@ To develop on hackertray, or to test out experimental versions, do the following - Run `hackertray` with the required command line options from anywhere. ##Analytics -TO help improve the project and learn how its being used, I've added Analytics in hackertray. The `--dnt` switch disables all analytics so that you can opt-out if desired. All data is collected anonymously, with no machine id or user-identifying information being sent back. To learn more, and see which events are being tracked, see the [Analytics](wiki/Analytics) wiki page. +To help improve the project and learn how its being used, I've added Analytics in hackertray. The `--dnt` switch disables all analytics so that you can opt-out if desired. All data is collected anonymously, with no machine id or user-identifying information being sent back. To learn more, and see which events are being tracked, see the [Analytics](wiki/Analytics) wiki page. ##Credits From b9ebeaebce1a30ba652e1d2e320f53af56efd055 Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 07:44:32 +0530 Subject: [PATCH 6/8] Tracks url visit event --- hackertray/__init__.py | 4 ++++ hackertray/analytics.py | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hackertray/__init__.py b/hackertray/__init__.py index d4ccd3b..8a6e713 100644 --- a/hackertray/__init__.py +++ b/hackertray/__init__.py @@ -119,11 +119,13 @@ class HackerNewsApp: webbrowser.open(HackerNewsApp.UPDATE_URL) # Remove the update button once clicked self.menu.remove(widget) + Analytics.visit(HackerNewsApp.UPDATE_URL) def showAbout(self, widget): """Handle the about btn""" webbrowser.open(HackerNewsApp.ABOUT_URL) + Analytics.visit(HackerNewsApp.ABOUT_URL) #ToDo: Handle keyboard interrupt properly def quit(self, widget, data=None): @@ -136,6 +138,7 @@ class HackerNewsApp: file.write(json.dumps(l)) gtk.main_quit() + Analytics.track('quit') def run(self): signal.signal(signal.SIGINT, self.quit) @@ -156,6 +159,7 @@ class HackerNewsApp: if self.commentState: webbrowser.open(self.HN_URL_PREFIX + widget.hn_id) + Analytics.visit(widget.url) def addItem(self, item): """Adds an item to the menu""" diff --git a/hackertray/analytics.py b/hackertray/analytics.py index e7b453a..fae6189 100644 --- a/hackertray/analytics.py +++ b/hackertray/analytics.py @@ -17,4 +17,10 @@ class Analytics: def track(event, data = {}): if(Analytics.dnt == False): # All events are tracked anonymously - Analytics.tracker.track("anonymous", event, data) \ No newline at end of file + Analytics.tracker.track("anonymous", event, data) + # Track a visit to a URL + # The url maybe an HN submission or + # some meta-url pertaining to hackertray + @staticmethod + def visit(url): + Analytics.track('visit', url) \ No newline at end of file From 4edb2a2053e20060f1cf625e50bcefd1e0201106 Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Wed, 1 Oct 2014 16:25:07 +0530 Subject: [PATCH 7/8] Fixes link to analytics wiki page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35b67df..c0b817c 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ To develop on hackertray, or to test out experimental versions, do the following - Run `hackertray` with the required command line options from anywhere. ##Analytics -To help improve the project and learn how its being used, I've added Analytics in hackertray. The `--dnt` switch disables all analytics so that you can opt-out if desired. All data is collected anonymously, with no machine id or user-identifying information being sent back. To learn more, and see which events are being tracked, see the [Analytics](wiki/Analytics) wiki page. +To help improve the project and learn how its being used, I've added Analytics in hackertray. The `--dnt` switch disables all analytics so that you can opt-out if desired. All data is collected anonymously, with no machine id or user-identifying information being sent back. To learn more, and see which events are being tracked, see the [Analytics](https://github.com/captn3m0/hackertray/wiki/Analytics) wiki page. ##Credits From 0c314e690ba7de08242bd29e744e152779ff98cc Mon Sep 17 00:00:00 2001 From: Abhay Rana Date: Thu, 2 Oct 2014 13:28:39 +0530 Subject: [PATCH 8/8] Fixes a minor bug with the visit event - Analytics is no longer static. --- hackertray/__init__.py | 12 ++++++------ hackertray/analytics.py | 21 +++++++++------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/hackertray/__init__.py b/hackertray/__init__.py index 8a6e713..53b1668 100644 --- a/hackertray/__init__.py +++ b/hackertray/__init__.py @@ -47,7 +47,7 @@ class HackerNewsApp: self.db = set() # Setup analytics - Analytics.setup(args.dnt, HackerNewsApp.MIXPANEL_TOKEN) + self.tracker = Analytics(args.dnt, HackerNewsApp.MIXPANEL_TOKEN) # create an indicator applet self.ind = appindicator.Indicator("Hacker Tray", "hacker-tray", appindicator.CATEGORY_APPLICATION_STATUS) @@ -108,7 +108,7 @@ class HackerNewsApp: launch_data['browser'] = subprocess.check_output(["xdg-settings","get","default-web-browser"]).strip() except subprocess.CalledProcessError as e: launch_data['browser'] = "unknown" - Analytics.track('launch', launch_data) + self.tracker.track('launch', launch_data) def toggleComments(self, widget): """Whether comments page is opened or not""" @@ -119,13 +119,13 @@ class HackerNewsApp: webbrowser.open(HackerNewsApp.UPDATE_URL) # Remove the update button once clicked self.menu.remove(widget) - Analytics.visit(HackerNewsApp.UPDATE_URL) + self.tracker.visit(HackerNewsApp.UPDATE_URL) def showAbout(self, widget): """Handle the about btn""" webbrowser.open(HackerNewsApp.ABOUT_URL) - Analytics.visit(HackerNewsApp.ABOUT_URL) + self.tracker.visit(HackerNewsApp.ABOUT_URL) #ToDo: Handle keyboard interrupt properly def quit(self, widget, data=None): @@ -138,7 +138,7 @@ class HackerNewsApp: file.write(json.dumps(l)) gtk.main_quit() - Analytics.track('quit') + self.tracker.track('quit') def run(self): signal.signal(signal.SIGINT, self.quit) @@ -159,7 +159,7 @@ class HackerNewsApp: if self.commentState: webbrowser.open(self.HN_URL_PREFIX + widget.hn_id) - Analytics.visit(widget.url) + self.tracker.visit(widget.url) def addItem(self, item): """Adds an item to the menu""" diff --git a/hackertray/analytics.py b/hackertray/analytics.py index fae6189..f1437aa 100644 --- a/hackertray/analytics.py +++ b/hackertray/analytics.py @@ -4,23 +4,20 @@ class Analytics: # Setup analytics. # dnt - do not track. Disables tracking if True # token - The mixpanel token - @staticmethod - def setup(dnt, token): - Analytics.dnt = dnt - Analytics.tracker = Mixpanel(token) - if(dnt == True): + def __init__(self, dnt, token): + self.dnt = dnt + self.tracker = Mixpanel(token) + if(self.dnt == True): print "[+] Analytics disabled" # Track an event # event - string containing the event name # data - data related to the event, defaults to {} - @staticmethod - def track(event, data = {}): - if(Analytics.dnt == False): + def track(self, event, data = {}): + if(self.dnt == False): # All events are tracked anonymously - Analytics.tracker.track("anonymous", event, data) + self.tracker.track("anonymous", event, data) # Track a visit to a URL # The url maybe an HN submission or # some meta-url pertaining to hackertray - @staticmethod - def visit(url): - Analytics.track('visit', url) \ No newline at end of file + def visit(self, url): + self.track('visit', {"link":url}) \ No newline at end of file