Created
December 16, 2015 12:53
-
-
Save noqqe/5420d1d95aad95d4f66c to your computer and use it in GitHub Desktop.
commandline bookmark manager in python and mongodb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2.7 | |
""" bm 1.0.0 | |
Usage: | |
bm list | |
bm search <pattern> | |
bm add <url> <tags>... [--date=<date>] | |
bm stats | |
bm tags | |
Options: | |
--date=<date> specifiy date manually | |
--version show version | |
--help show help | |
""" | |
import re | |
import datetime | |
import urllib2 | |
import ssl | |
import pymongo | |
from dateutil.parser import parse | |
from bs4 import BeautifulSoup | |
from docopt import docopt | |
from bson.objectid import ObjectId | |
from termcolor import cprint | |
# LOL SECURITY | |
ssl._create_default_https_context = ssl._create_unverified_context | |
class Links(object): | |
"""Docstring for Links. """ | |
def __init__(self): | |
self.db = self._mcon() | |
# private | |
def _mcon(self): | |
""" Initialize MongoDB Connection | |
:returns: collection object | |
""" | |
c = pymongo.MongoClient('localhost', 27017) | |
db = c.links.links | |
return db | |
def _display(self, r): | |
""" Display an MongoDB document """ | |
cprint("title: ", end='') | |
cprint(r["title"], 'green', attrs=['bold']) | |
print(" url: " + r["url"]) | |
print(" tags: "), | |
for e in r["tags"]: | |
cprint(e, 'white', attrs=['bold'], end=' ') | |
print("") | |
print(" date: " + r["date"].strftime('%Y-%m-%d %H:%M')) | |
print("") | |
return True | |
def _fetchtitle(self, url): | |
""" Fetch <title> of a html site for title element | |
:returns: string | |
""" | |
try: | |
h = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'} | |
u = urllib2.Request(url, headers=h) | |
u = urllib2.urlopen(u) | |
soup = BeautifulSoup(u) | |
s = soup.title.string.replace('\n', ' ').replace('\r', '') | |
return s | |
except (AttributeError, MemoryError, ssl.CertificateError, IOError) as e: | |
return "No title" | |
def _checkdup(self, url): | |
""" Check if url already exists in db | |
:returns: bool | |
""" | |
db = self.db | |
if db.find({"url": url}).count() > 0: | |
return True | |
else: | |
return False | |
# public | |
def add(self, url, tags, date): | |
""" Add bookmark to MongoDB | |
:returns: bool | |
""" | |
db = self.db | |
if self._checkdup(url) is True: | |
cprint("INFO: Duplicate found", 'yellow') | |
return False | |
title = self._fetchtitle(url) | |
if title is not False: | |
item = {"url": url, | |
"title": title, | |
"tags": tags, | |
"date": date} | |
objid = db.insert_one(item).inserted_id | |
print("") | |
for r in db.find({"_id": ObjectId(objid)}): | |
self._display(r) | |
else: | |
cprint("Error: Failed fetching " + url, 'red') | |
return True | |
def list(self): | |
""" list bookmarks in MongoDB | |
:returns: bool | |
""" | |
db = self.db | |
print("") | |
for r in db.find().sort("date", 1): | |
self._display(r) | |
return True | |
def search(self, pattern): | |
""" search for bookmarks in MongoDB | |
:returns: bool | |
""" | |
db = self.db | |
p = re.compile(pattern, re.IGNORECASE) | |
query = {"$or": | |
[{"title": {"$regex": p}}, | |
{"url": {"$regex": p}}, | |
{"tags": p} | |
] | |
} | |
print("") | |
for r in db.find(query).sort("date", 1): | |
self._display(r) | |
return True | |
def stats(self): | |
""" Show statistics about bookmarks | |
:returns: True | |
""" | |
db = self.db | |
num = db.find().count() | |
print("Links total: %s" % num) | |
tags = db.find({},{"tags": 1}) | |
mlist = [] | |
tagcount = 0 | |
for t in tags: | |
mlist = list(set(mlist + t["tags"])) | |
tagcount += len(t["tags"]) | |
print("Tags Total: %s" % tagcount) | |
print("Unique Tags: %s" % len(mlist)) | |
print("Links per year:") | |
for x in range(2010,2018): | |
start = datetime.datetime(x, 1, 1, 0, 0, 0, 557000); | |
end = datetime.datetime(x + 1, 1, 1, 0, 0, 0, 557000); | |
y = db.find({"date": {'$gt': start, '$lt': end}}).count() | |
if y > 0: | |
print(" %s: %s" % (x,y)) | |
return True | |
def tags(self): | |
""" Show all of the tags | |
:returns: True | |
""" | |
db = self.db | |
tags = db.find({},{"tags": 1}) | |
mlist = [] | |
for t in tags: | |
mlist = list(set(mlist + t["tags"])) | |
cprint("Tags:", 'green', attrs={"bold"}) | |
for m in mlist: | |
print(m) | |
return True | |
if __name__ == '__main__': | |
args = docopt(__doc__, version='bm') | |
if args['--date'] is not None: | |
d = parse(args['--date']) | |
else: | |
d = datetime.datetime.now() | |
if args['list'] is True: | |
Links().list() | |
if args['add'] is True: | |
Links().add(url=args['<url>'], tags=args['<tags>'], date=d) | |
if args['search'] is True: | |
Links().search(args['<pattern>']) | |
if args['stats'] is True: | |
Links().stats() | |
if args['tags'] is True: | |
Links().tags() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment