Re: [Deskbar] desklicious :)



On Thu, 2006-03-16 at 04:52 -0500, Francisco Jesús Jordano Jiménez
wrote:

Hi Francisco !

> I've developed a handler for personal del.icio.us bookmarks.
> It searchs your bookmarks looking for the tags you type in the deskbar.
> 
> The attach contains the handler and a png for displaying results :). If you wanna test it you should set in the handler your delicious user and password.
> 
> If you have any question of suggestion about this handler please tell me :)

I have modified and updated your handler to be a bit more consistent
with the way deskbar works now. I attach the handler to this mail so
everyone can enjoy it.

Now we should decide wether we want this in the deskbar package or if it
should be distributed outside (by word of mouth, currently..)

My guess is, let's include it for now until we find a way to properly
install external (from-the-web) handlers..

Opinions ?
Thanks again for your work !
Raf
import os, cgi, os.path, deskbar, deskbar.Match, deskbar.Handler
import gnomevfs, gtk

from gettext import gettext as _

import urllib2,base64,libxml2,sys

GCONF_DELICIOUS_USER  = deskbar.GCONF_DIR+"/desklicious/user"
GCONF_DELICIOUS_PASS  = deskbar.GCONF_DIR+"/desklicious/pass"

DEFAULT_QUERY_TAG = "http://del.icio.us/api/posts/all?tag";
MAX_QUERIES = 10
QUERY_DELAY = 1

def _check_requirements():
	#We need user and password
	if not deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_USER) or not deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_PASS):
		return (deskbar.Handler.HANDLER_HAS_REQUIREMENTS, _("You need to configure your deli.icio.us account."), _on_config_account)
	else:
		return (deskbar.Handler.HANDLER_IS_CONFIGURABLE, _("You can modify your deli.icio.us account."), _on_config_account)

HANDLERS = {
	"DeliciousHandler" : {
		"name": _("del.icio.us Bookmarks"),
		"description": _("Search your del.icio.us bookmarks by tag name"),
		"requirements" : _check_requirements
	}
}

def _on_config_account(dialog):
	dialog = gtk.Dialog(_("del.icio.us Account"), dialog,
				gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
				(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
				gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
	
	table = gtk.Table(rows=3, columns=2)
	
	table.attach(gtk.Label(_("Enter your deli.icio.us username and password below")), 0, 2, 0, 1)

	user_entry = gtk.Entry()
	user_entry.set_text(deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_USER))
	table.attach(gtk.Label(_("Username: ")), 0, 1, 1, 2)
	table.attach(user_entry, 1, 2, 1, 2)
	
	pass_entry = gtk.Entry()
	pass_entry.set_text(deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_PASS))
	pass_entry.set_visibility(False)
	table.attach(gtk.Label(_("Password: ")), 0, 1, 2, 3)
	table.attach(pass_entry, 1, 2, 2, 3)
	table.show_all()
	dialog.vbox.add(table)
	
	response = dialog.run()
	dialog.destroy()
	
	if response == gtk.RESPONSE_ACCEPT and user_entry.get_text() != "" and pass_entry.get_text() != "":
		deskbar.GCONF_CLIENT.set_string(GCONF_DELICIOUS_USER, user_entry.get_text())
		deskbar.GCONF_CLIENT.set_string(GCONF_DELICIOUS_PASS, pass_entry.get_text())

class DeliciousMatch(deskbar.Match.Match):	
	def __init__(self, handler, url=None, tags=None, extended=None, **args):
		deskbar.Match.Match.__init__ (self, handler, **args)
		self.url = url
		self.tags = tags
		self.extended = extended
		
	def get_verb(self):
		return "<b>%(name)s</b>\n<span size='small' foreground='grey'>%(tags)s</span>"
	
	def get_name(self, text=None):
		return {
			"name": cgi.escape(self.name),
			"tags": cgi.escape(' '.join(self.tags)),
		}
		
	def action(self, text=None):
		gnomevfs.url_show(self.url)

	def get_category(self):
		return "web"

	def get_hash(self, text=None):
		return self.url
		
class DeliciousHandler(deskbar.Handler.AsyncHandler):
	def __init__(self):
		deskbar.Handler.AsyncHandler.__init__ (self, os.path.join(os.path.dirname(__file__), "delicious.png"))
		self._delicious = DeliciousTagQueryEngine(self)

	def query(self, tag):
		#Hey man, calm down and query once a time :P
		self.check_query_changed (timeout=QUERY_DELAY)
		
		qmax = min (deskbar.DEFAULT_RESULTS_PER_HANDLER, MAX_QUERIES)
		
		# Yes, the google and yahoo search might take a long time
		# and of course deliciuos too !!! ... better check if we're still valid	
		self.check_query_changed ()
		
		#The queryyyyYyyYy :)
		print "Asking del.icio.us tags for %s" % tag
		posts = self._delicious.get_posts_by_tag(tag)
				
		self.check_query_changed ()
		
		return posts[:qmax]

class DeliciousTagQueryEngine:	
	def __init__(self, handler):
		"""We need use the globals DELICIOUS_USER and DELICIOUS_PASS"""
		self.handler = handler
		
		self._user = deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_USER)
		self._pass = deskbar.GCONF_CLIENT.get_string(GCONF_DELICIOUS_PASS)
			
		deskbar.GCONF_CLIENT.notify_add(GCONF_DELICIOUS_USER, lambda x, y, z, a: self.on_username_change(z.value))
		deskbar.GCONF_CLIENT.notify_add(GCONF_DELICIOUS_PASS, lambda x, y, z, a: self.on_pass_change(z.value))
		
	def on_username_change(self, value):
		if value != None and value.type == gconf.VALUE_STRING:
			self._user = value.get_string()
	
	def on_pass_change(self, value):
		if value != None and value.type == gconf.VALUE_STRING:
			self._pass = value.get_string()
			
	def get_posts_by_tag(self, tag):
		url = "%s=%s" % (DEFAULT_QUERY_TAG, tag)
		#Get the info from del.icio.us and parse
		xml = libxml2.parseDoc(self._get_delicious_url(url))
		postsXML = xml.xpathEval("/posts/post")
		
		#And return the results
		posts=[]
		for post in postsXML:
			posts.append(
				DeliciousMatch(self.handler,
					name=post.prop('description'),
					url=post.prop('href'),
					tags=post.prop('tag').split(" "),
					extended=post.prop('extended')))
		
		return posts
		
	def _get_delicious_url(self, url):
		req = urllib2.Request(url)
		try:
			handle = urllib2.urlopen(req)
		except IOError, e:				  
			#We need to authenticate
			base64string = base64.encodestring('%s:%s' % (self._user, self._pass))[:-1]
			authheader =  "Basic %s" % base64string
			req.add_header("Authorization", authheader)
			try:
				handle = urllib2.urlopen(req)
			except IOError, e:				  
				#User or Pass invalid!!!
				print "Desklicious info ::: user or pass invalid, please check your params."
				return None
			return handle.read()   
		
		else:
			#We do not need authentication
			return handle.read()
			
class DeliciousPost:
	def __init__(self,data):
		self.description=data.prop('description')
		self.href=data.prop('href')
		self.tags=data.prop('tag').split(" ")
		self.extended=data.prop('extended')

Attachment: signature.asc
Description: This is a digitally signed message part



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]