Merge branch 'firefox'

Conflicts:
	hackertray/chrome.py
This commit is contained in:
Abhay Rana 2014-10-03 19:10:06 +05:30
commit 4224c9c198
7 changed files with 94 additions and 16 deletions

19
.editorconfig Normal file
View File

@ -0,0 +1,19 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

View File

@ -57,6 +57,9 @@ 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. 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. 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. `--firefox PROFILE_PATH`: Specify path to a firefox profile directory. HackerTray will read your firefox history from this profile, and use it to mark links as read.
Note that the `--chrome` and `--firefox` options are independent, and can be used together. However, they cannot be specified multiple times (so reading from 2 chrome profiles is not possible).
###Google Chrome Profile Path ###Google Chrome Profile Path
@ -68,6 +71,9 @@ Where your Profile is stored depends on which version of chrome you are using:
Replace `Default` with `Profile 1`, `Profile 2` or so on if you use multiple profiles on Chrome. Note that the `--chrome` option accepts a `PROFILE_PATH`, not the History file itself. Also note that sometimes `~` might not be set, so you might need to use the complete path (such as `/home/nemo/.config/google-chrome/Default/`). Replace `Default` with `Profile 1`, `Profile 2` or so on if you use multiple profiles on Chrome. Note that the `--chrome` option accepts a `PROFILE_PATH`, not the History file itself. Also note that sometimes `~` might not be set, so you might need to use the complete path (such as `/home/nemo/.config/google-chrome/Default/`).
###Firefox Profile Path
The default firefox profile path is `~/.mozilla/firefox/*.default`, where `*` denotes a random 8 digit string. You can also read `~/.mozilla/firefox/profiles.ini` to get a list of profiles.
##Features ##Features
1. Minimalist Approach to HN 1. Minimalist Approach to HN
2. Opens links in your default browser 2. Opens links in your default browser

View File

@ -25,6 +25,7 @@ import signal
from hackernews import HackerNews from hackernews import HackerNews
from chrome import Chrome from chrome import Chrome
from firefox import Firefox
from version import Version from version import Version
class HackerNewsApp: class HackerNewsApp:
@ -89,7 +90,7 @@ class HackerNewsApp:
self.menu.show() self.menu.show()
self.ind.set_menu(self.menu) self.ind.set_menu(self.menu)
self.refresh(chrome_data_directory=args.chrome) self.refresh(chrome_data_directory=args.chrome, firefox_data_directory=args.firefox)
def toggleComments(self, widget): def toggleComments(self, widget):
"""Whether comments page is opened or not""" """Whether comments page is opened or not"""
@ -159,14 +160,19 @@ class HackerNewsApp:
self.menu.prepend(i) self.menu.prepend(i)
i.show() i.show()
def refresh(self, widget=None, no_timer=False, chrome_data_directory=None): def refresh(self, widget=None, no_timer=False, chrome_data_directory=None, firefox_data_directory=None):
"""Refreshes the menu """ """Refreshes the menu """
try: try:
# Create an array of 20 false to denote matches in History
searchResults = [False]*20
data = list(reversed(HackerNews.getHomePage()[0:20])) data = list(reversed(HackerNews.getHomePage()[0:20]))
urls = [item['url'] for item in data]
if(chrome_data_directory): if(chrome_data_directory):
urls = [item['url'] for item in data] searchResults = self.mergeBoolArray(searchResults, Chrome.search(urls, chrome_data_directory))
searchResults = Chrome.search(urls, chrome_data_directory)
if(firefox_data_directory):
searchResults = self.mergeBoolArray(searchResults, Firefox.search(urls, firefox_data_directory))
#Remove all the current stories #Remove all the current stories
for i in self.menu.get_children(): for i in self.menu.get_children():
@ -175,10 +181,7 @@ class HackerNewsApp:
#Add back all the refreshed news #Add back all the refreshed news
for index, item in enumerate(data): for index, item in enumerate(data):
if(chrome_data_directory): item['history'] = searchResults[index]
item['history'] = searchResults[index]
else:
item['history'] = False
self.addItem(item) self.addItem(item)
# Catch network errors # Catch network errors
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
@ -188,13 +191,18 @@ class HackerNewsApp:
if not no_timer: if not no_timer:
gtk.timeout_add(10 * 30 * 1000, self.refresh, widget, no_timer, chrome_data_directory) gtk.timeout_add(10 * 30 * 1000, self.refresh, widget, no_timer, chrome_data_directory)
# Merges two boolean arrays, using OR operation against each pair
def mergeBoolArray(self, original, patch):
for index, var in enumerate(original):
original[index] = original[index] or patch[index]
return original
def main(): def main():
parser = argparse.ArgumentParser(description='Hacker News in your System Tray') parser = argparse.ArgumentParser(description='Hacker News in your System Tray')
parser.add_argument('-v','--version', action='version', version=Version.current()) 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('-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('--chrome', dest='chrome', help="Specify a Google Chrome Profile directory to use for matching chrome history")
parser.add_argument('--firefox', dest='firefox', help="Specify a Firefox Profile directory to use for matching firefox history")
parser.set_defaults(comments=False) parser.set_defaults(comments=False)
args = parser.parse_args() args = parser.parse_args()
indicator = HackerNewsApp(args) indicator = HackerNewsApp(args)

30
hackertray/firefox.py Normal file
View File

@ -0,0 +1,30 @@
from __future__ import print_function
import sqlite3
import shutil
import os
import sys
class Firefox:
HISTORY_TMP_LOCATION = '/tmp/hackertray.firefox'
HISTORY_FILE_NAME = '/places.sqlite'
@staticmethod
def search(urls, config_folder_path):
Firefox.setup(config_folder_path)
conn = sqlite3.connect(Firefox.HISTORY_TMP_LOCATION)
db = conn.cursor()
result = []
for url in urls:
db_result = db.execute('SELECT url from moz_places WHERE url=:url',{"url":url})
if(db.fetchone() == None):
result.append(False)
else:
result.append(True)
os.remove(Firefox.HISTORY_TMP_LOCATION)
return result
@staticmethod
def setup(config_folder_path):
file_name = os.path.abspath(config_folder_path+Firefox.HISTORY_FILE_NAME)
if not os.path.isfile(file_name):
print("ERROR: ", "Could not find Firefox history file", file=sys.stderr)
sys.exit(1)
shutil.copyfile(file_name, Firefox.HISTORY_TMP_LOCATION)

View File

@ -5,11 +5,11 @@ from hackertray import Chrome
class ChromeTest(unittest.TestCase): class ChromeTest(unittest.TestCase):
def runTest(self): def runTest(self):
config_folder_path = os.getcwd()+'/test/' config_folder_path = os.getcwd()+'/test/'
data = Chrome.search([ data = Chrome.search([
"https://github.com/", "https://github.com/",
"https://news.ycombinator.com/", "https://news.ycombinator.com/",
"https://github.com/captn3m0/hackertray", "https://github.com/captn3m0/hackertray",
"http://invalid_url/"], "http://invalid_url/"],
config_folder_path) config_folder_path)
self.assertTrue(data == [True,True,True,False]) self.assertTrue(data == [True,True,True,False])

15
test/firefox_test.py Normal file
View File

@ -0,0 +1,15 @@
import unittest
import os
from hackertray import Firefox
class ChromeTest(unittest.TestCase):
def runTest(self):
config_folder_path = os.getcwd()+'/test/'
data = Firefox.search([
"http://www.hckrnews.com/",
"http://www.google.com/",
"http://wiki.ubuntu.com/",
"http://invalid_url/"],
config_folder_path)
self.assertTrue(data == [True,True,True,False])

BIN
test/places.sqlite Normal file

Binary file not shown.