|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Mitter, a micro-blogging client with multiple interfaces.
|
|
|
|
# Copyright (C) 2007-2010 Mitter Contributors
|
|
|
|
#
|
|
|
|
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import urllib2
|
|
|
|
|
|
|
|
import gtk
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
# Constants
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
_log = logging.getLogger('ui.helpers.avatarcache')
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
# The cache class
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
class AvatarCache(object):
|
|
|
|
"""An avatar cache, storing GDK pixbufs references."""
|
|
|
|
|
|
|
|
def __init__(self, connection, default, timeout=None):
|
|
|
|
"""Initialization of the cache.
|
|
|
|
|
|
|
|
connection:
|
|
|
|
A :class:`ThreadManager`, which will be used as thread pool to
|
|
|
|
request the avatars.
|
|
|
|
|
|
|
|
default:
|
|
|
|
A gdk_pixbuf to be used as placeholder while the real avatar is
|
|
|
|
being downloaded.
|
|
|
|
|
|
|
|
timeout:
|
|
|
|
Request timeout when downloading the avatars."""
|
|
|
|
|
|
|
|
self._connection = connection
|
|
|
|
self._default = default
|
|
|
|
self._cache = {}
|
|
|
|
self._timeout = timeout
|
|
|
|
|
|
|
|
def get(self, owner, avatar, url=None):
|
|
|
|
"""Return the avatar from the cache or, if the avatar isn't available
|
|
|
|
yet, returns the default avatar and queue the download of it.
|
|
|
|
|
|
|
|
owner:
|
|
|
|
The object requesting the avatar. Must have a "queue_draw()"
|
|
|
|
method, which will be called once the avatar is available. Can be
|
|
|
|
None.
|
|
|
|
|
|
|
|
avatar:
|
|
|
|
The identification of the avatar. Can be any string.
|
|
|
|
|
|
|
|
url:
|
|
|
|
URL to download the avatar. If not passed, *avatar* **must** be a
|
|
|
|
valid URL."""
|
|
|
|
|
|
|
|
if avatar in self._cache:
|
|
|
|
return self._cache[avatar]
|
|
|
|
|
|
|
|
if not url:
|
|
|
|
url = avatar
|
|
|
|
|
|
|
|
self._connection.add_work(self._post_avatar_download,
|
|
|
|
self._exception_avatar_download,
|
|
|
|
self._download_pic,
|
|
|
|
avatar,
|
|
|
|
url,
|
|
|
|
owner)
|
|
|
|
|
|
|
|
# add the default avatar in the cache just to avoid a new request for
|
|
|
|
# it. It will be overwritten anyway later.
|
|
|
|
self._cache[avatar] = self._default
|
|
|
|
return self._default
|
|
|
|
|
|
|
|
# ------------------------------------------------------------
|
|
|
|
# Network functions
|
|
|
|
# ------------------------------------------------------------
|
|
|
|
def _download_pic(self, avatar, url, owner):
|
|
|
|
"""Download a picture from the web. Can be used in a thread."""
|
|
|
|
request = urllib2.Request(url=url)
|
|
|
|
timeout = self._timeout
|
|
|
|
_log.debug('Starting request of %s (timeout %ds)' % (
|
|
|
|
url, timeout))
|
|
|
|
try:
|
|
|
|
response = urllib2.urlopen(request, timeout=timeout)
|
|
|
|
except TypeError, e:
|
|
|
|
# Python 2.5 doesn't have a timeout parameter
|
|
|
|
response = urllib2.urlopen(request)
|
|
|
|
data = response.read()
|
|
|
|
_log.debug('Request completed')
|
|
|
|
return (avatar, owner, data)
|
|
|
|
|
|
|
|
def _post_avatar_download(self, widget, data):
|
|
|
|
"""Called after the data from the picture is available."""
|
|
|
|
(avatar, owner, data) = data
|
|
|
|
|
|
|
|
loader = gtk.gdk.PixbufLoader()
|
|
|
|
loader.write(data)
|
|
|
|
loader.close()
|
|
|
|
|
|
|
|
user_pic = loader.get_pixbuf()
|
|
|
|
user_pic = user_pic.scale_simple(48, 48, gtk.gdk.INTERP_BILINEAR)
|
|
|
|
self._cache[avatar] = user_pic
|
|
|
|
|
|
|
|
if owner:
|
|
|
|
owner.queue_draw()
|
|
|
|
return
|
|
|
|
|
|
|
|
def _exception_avatar_download(self, widget, exception):
|
|
|
|
"""Called in case we have a problem downloading an user avatar."""
|
|
|
|
_log.debug('Exception trying to get an avatar.')
|
|
|
|
_log.debug(str(exception))
|
|
|
|
return
|