""" Flickr photo search for Deskbar Copyright (C) 2007 Fabio Corneti This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA A full copy of the GPL can be found at this URL: http://www.fsf.org/licensing/licenses/gpl.txt Initial ideas and stucture for this plugin provided by desklicious, included in the standard Deskbar plugins. """ import os, cgi, os.path, deskbar, deskbar.Match, deskbar.Handler, deskbar.Utils import gnomevfs, gtk, gconf from gettext import gettext as _ import xml.dom.minidom, urllib VERSION='0.1.1' FLICKR_REQUEST_TEMPLATE = 'http://api.flickr.com/services/feeds/photos_public.gne?tags=%s&format=rss_200' GCONF_MAX_RESULTS = deskbar.GCONF_DIR + '/flickr/maxresults' QUERY_DELAY = 1 THUMBNAIL_WIDTH = 75 MAX_RESULTS_RANGE_MAX = 64; _debug=True if _debug: import traceback def _check_requirements(): return (deskbar.Handler.HANDLER_IS_CONFIGURABLE, _("You can set the maximum number of results to return."), _on_config_account) HANDLERS = { "FlickrHandler" : { "name": _("Flickr photo search"), "description": _("Search photos on Flickr."), "requirements" : _check_requirements, "version": VERSION, } } class ThumbnailsCache(): def __init__(self): self._cache = {} def put(self, url, pixbuf): self._cache[url] = pixbuf def get(self, url): return self._cache.get(url, None) def has_key(self, key): return key in self._cache.keys() def purge(self): self._cache = {} thumbnailsCache = ThumbnailsCache() def _on_config_account(dialog): dialog = gtk.Dialog(_("Flickr photo search preferences"), 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=2, columns=2) table.attach(gtk.Label(_("Enter the maximum number of search results")), 0, 2, 0, 1) maxResultsAdjustment = gtk.Adjustment(value=0, lower=0, upper=MAX_RESULTS_RANGE_MAX, step_incr=1, page_incr=10, page_size=0) maxResultsSpinButton = gtk.SpinButton(adjustment=maxResultsAdjustment) maxResults = deskbar.GCONF_CLIENT.get_int(GCONF_MAX_RESULTS) maxResultsSpinButton.set_value(maxResults) table.attach(gtk.Label(_("Max results: ")), 0, 1, 1, 2) table.attach(maxResultsSpinButton, 1, 2, 1, 2) table.show_all() dialog.vbox.add(table) response = dialog.run() dialog.destroy() try: maxResults = int(maxResultsSpinButton.get_value()) except: maxResults = 0 if response == gtk.RESPONSE_ACCEPT: deskbar.GCONF_CLIENT.set_int(GCONF_MAX_RESULTS, maxResults) class FlickrMatch(deskbar.Match.Match): def __init__(self, handler, url=None, tags=None, author=None, thumbnail=None, **args): deskbar.Match.Match.__init__ (self, handler, **args) self.url = url self.tags = tags self.author = author self.thumbnail = thumbnail def get_verb(self): return "%(name)s\n%(author)s\n%(tags)s" def get_name(self, text=None): return { "name": cgi.escape(self.name), "thumbnail" : self.thumbnail, "author" : self.author, "tags": cgi.escape(' '.join(self.tags)), } def action(self, text=None): deskbar.Utils.url_show(self.url) def get_category(self): return "web" def get_hash(self, text=None): return self.url def get_icon(self): if thumbnailsCache.has_key(self.thumbnail): return thumbnailsCache.get(self.thumbnail) else: thumb = urllib.urlopen(self.thumbnail, proxies=deskbar.Utils.get_proxy()) data = thumb.read() pixbufLoader = gtk.gdk.PixbufLoader() pixbufLoader.write(data) pixbuf = pixbufLoader.get_pixbuf() pixbufLoader.close() if pixbuf.get_width() > 1: w = h = THUMBNAIL_WIDTH #TODO: implement scaling thumbnailsCache.put(self.thumbnail, pixbuf); return pixbuf else: return deskbar.Match.Match.get_icon(self) class FlickrHandler(deskbar.Handler.AsyncHandler): def __init__(self): deskbar.Handler.AsyncHandler.__init__ (self, "yahoo.png") self._flickrClient = FlickrClient(self) def query(self, tag): thumbnailsCache.purge() self.check_query_changed (timeout=QUERY_DELAY) self.check_query_changed () images = self._flickrClient.getPhotosByTag(tag) self.check_query_changed (timeout=QUERY_DELAY) return images class FlickrClient: def __init__(self, handler): self.handler = handler def getPhotosByTag(self, tag): maxResults = deskbar.GCONF_CLIENT.get_int(GCONF_MAX_RESULTS) photos=[] url = "http://api.flickr.com/services/feeds/photos_public.gne?tags=%s&format=rss_200" % urllib.quote_plus(tag) stream = urllib.urlopen(url, proxies=deskbar.Utils.get_proxy()) dom = xml.dom.minidom.parse(stream) stream.close() resultsCount = 0 for item in dom.getElementsByTagName("item"): if maxResults > 0 and resultsCount == maxResults: break photos.append( FlickrMatch(self.handler, name=item.getElementsByTagName("title")[0].firstChild.nodeValue, url=item.getElementsByTagName("link")[0].firstChild.nodeValue, tags=item.getElementsByTagName("media:category")[0].firstChild.nodeValue.split(" "), author=item.getElementsByTagName("author")[0].firstChild.nodeValue, thumbnail=item.getElementsByTagName("media:thumbnail")[0].attributes["url"].nodeValue)) resultsCount = resultsCount + 1 return photos