Commit 1fc464f1 authored by Dan Pascu's avatar Dan Pascu

Store Google contact icons in the IconManager

parent cda52677
...@@ -440,13 +440,6 @@ class GoogleContactID(unicode): ...@@ -440,13 +440,6 @@ class GoogleContactID(unicode):
pass pass
class GoogleContactIconData(bytes):
def __new__(cls, data, url):
instance = super(GoogleContactIconData, cls).__new__(cls, data)
instance.url = url
return instance
class GoogleContactIconMetadata(object): class GoogleContactIconMetadata(object):
def __init__(self, metadata): def __init__(self, metadata):
metadata = metadata or {'source': {'id': None, 'type': None}} metadata = metadata or {'source': {'id': None, 'type': None}}
...@@ -457,31 +450,10 @@ class GoogleContactIconMetadata(object): ...@@ -457,31 +450,10 @@ class GoogleContactIconMetadata(object):
class GoogleContactIcon(object): class GoogleContactIcon(object):
def __init__(self, url, metadata, data=None): def __init__(self, url, metadata):
self.url = url self.url = url
self.metadata = GoogleContactIconMetadata(metadata) self.metadata = GoogleContactIconMetadata(metadata)
self.data = data self.downloaded_url = None
@property
def url(self):
return self.__dict__['url']
@url.setter
def url(self, value):
old_value = self.__dict__.get('url')
new_value = self.__dict__['url'] = value
if old_value != new_value is None:
self.data = None
@property
def data(self):
return self.__dict__['data']
@data.setter
def data(self, value):
if not isinstance(value, (GoogleContactIconData, type(None))):
raise TypeError("data must be an instance of GoogleContactIconData or None")
self.__dict__['data'] = value
@property @property
def alternate_url(self): def alternate_url(self):
...@@ -492,7 +464,7 @@ class GoogleContactIcon(object): ...@@ -492,7 +464,7 @@ class GoogleContactIcon(object):
@property @property
def needs_update(self): def needs_update(self):
return self.url is not None and (self.data is None or self.data.url != self.url) return self.url != self.downloaded_url
class GoogleContactIconRetriever(object): class GoogleContactIconRetriever(object):
...@@ -512,12 +484,25 @@ class GoogleContactIconRetriever(object): ...@@ -512,12 +484,25 @@ class GoogleContactIconRetriever(object):
icon = self.contact.icon icon = self.contact.icon
http = self.credentials.authorize(Http(timeout=5)) http = self.credentials.authorize(Http(timeout=5))
try: try:
response, content = http.request(icon.url+'?size=96') if icon.url is not None:
response, content = http.request(icon.url+'?size={}'.format(IconManager.max_size))
else:
response = content = None
except (HttpLib2Error, socket.error) as e: except (HttpLib2Error, socket.error) as e:
log.warning(u"could not retrieve icon for {}: {!s}".format(self.contact.name, e)) log.warning(u"could not retrieve icon for {}: {!s}".format(self.contact.name, e))
else: else:
if response['status'] == '200' and response['content-type'].startswith('image/'): if response is None:
icon.data = GoogleContactIconData(content, icon.url) icon_manager = IconManager()
icon_manager.store_data(self.contact.id, None)
icon.downloaded_url = None
elif response['status'] == '200' and response['content-type'].startswith('image/'):
icon_manager = IconManager()
try:
icon_manager.store_data(self.contact.id, content)
except Exception as e:
log.error(u"could not store icon for {}: {!s}".format(self.contact.name, e))
else:
icon.downloaded_url = icon.url
elif response['status'] == '403' and icon.alternate_url: # private photo. use old GData protocol if alternate_url is available elif response['status'] == '403' and icon.alternate_url: # private photo. use old GData protocol if alternate_url is available
try: try:
response, content = http.request(icon.alternate_url, headers={'GData-Version': '3.0'}) response, content = http.request(icon.alternate_url, headers={'GData-Version': '3.0'})
...@@ -525,7 +510,13 @@ class GoogleContactIconRetriever(object): ...@@ -525,7 +510,13 @@ class GoogleContactIconRetriever(object):
log.warning(u"could not retrieve icon for {}: {!s}".format(self.contact.name, e)) log.warning(u"could not retrieve icon for {}: {!s}".format(self.contact.name, e))
else: else:
if response['status'] == '200' and response['content-type'].startswith('image/'): if response['status'] == '200' and response['content-type'].startswith('image/'):
icon.data = GoogleContactIconData(content, icon.url) icon_manager = IconManager()
try:
icon_manager.store_data(self.contact.id, content)
except Exception as e:
log.error(u"could not store icon for {}: {!s}".format(self.contact.name, e))
else:
icon.downloaded_url = icon.url
else: else:
log.error(u"could not retrieve icon for {} (status={}, content type={})".format(self.contact.name, response['status'], response['content-type'])) log.error(u"could not retrieve icon for {} (status={}, content type={})".format(self.contact.name, response['status'], response['content-type']))
else: else:
...@@ -1348,12 +1339,8 @@ class Contact(object): ...@@ -1348,12 +1339,8 @@ class Contact(object):
icon_manager = IconManager() icon_manager = IconManager()
icon = icon_manager.get(self.settings.id + '_alt') or icon_manager.get(self.settings.id) or self.default_user_icon icon = icon_manager.get(self.settings.id + '_alt') or icon_manager.get(self.settings.id) or self.default_user_icon
elif self.type == 'google': elif self.type == 'google':
pixmap = QPixmap() icon_manager = IconManager()
if pixmap.loadFromData(self.settings.icon.data): icon = icon_manager.get(self.settings.id) or self.default_user_icon
icon = QIcon(pixmap)
icon.filename = None # TODO: cache icons to disk -Saul
else:
icon = self.default_user_icon
else: else:
icon = self.default_user_icon icon = self.default_user_icon
return self.__dict__.setdefault('icon', icon) return self.__dict__.setdefault('icon', icon)
...@@ -1508,11 +1495,8 @@ class ContactDetail(object): ...@@ -1508,11 +1495,8 @@ class ContactDetail(object):
icon_manager = IconManager() icon_manager = IconManager()
icon = icon_manager.get(self.settings.id + '_alt') or icon_manager.get(self.settings.id) or self.default_user_icon icon = icon_manager.get(self.settings.id + '_alt') or icon_manager.get(self.settings.id) or self.default_user_icon
elif self.type == 'google': elif self.type == 'google':
pixmap = QPixmap() icon_manager = IconManager()
if pixmap.loadFromData(self.settings.icon.data): icon = icon_manager.get(self.settings.id) or self.default_user_icon
icon = QIcon(pixmap)
else:
icon = self.default_user_icon
else: else:
icon = self.default_user_icon icon = self.default_user_icon
return self.__dict__.setdefault('icon', icon) return self.__dict__.setdefault('icon', icon)
...@@ -2553,6 +2537,9 @@ class ContactModel(QAbstractListModel): ...@@ -2553,6 +2537,9 @@ class ContactModel(QAbstractListModel):
icon_manager = IconManager() icon_manager = IconManager()
icon_manager.remove(contact.settings.id) icon_manager.remove(contact.settings.id)
icon_manager.remove(contact.settings.id + '_alt') icon_manager.remove(contact.settings.id + '_alt')
elif notification.sender is GoogleContactsGroup():
icon_manager = IconManager()
icon_manager.remove(contact.settings.id)
def _NH_BlinkContactDidChange(self, notification): def _NH_BlinkContactDidChange(self, notification):
contact = notification.sender contact = notification.sender
......
...@@ -93,6 +93,7 @@ class IconManager(object): ...@@ -93,6 +93,7 @@ class IconManager(object):
@run_in_gui_thread(wait=True) @run_in_gui_thread(wait=True)
def get(self, id): def get(self, id):
id = id.replace('/', '_')
try: try:
return self.iconmap[id] return self.iconmap[id]
except KeyError: except KeyError:
...@@ -114,6 +115,7 @@ class IconManager(object): ...@@ -114,6 +115,7 @@ class IconManager(object):
@run_in_gui_thread(wait=True) @run_in_gui_thread(wait=True)
def store_data(self, id, data): def store_data(self, id, data):
id = id.replace('/', '_')
directory = ApplicationData.get('images') directory = ApplicationData.get('images')
filename = os.path.join(directory, id + '.png') filename = os.path.join(directory, id + '.png')
makedirs(directory) makedirs(directory)
...@@ -140,6 +142,7 @@ class IconManager(object): ...@@ -140,6 +142,7 @@ class IconManager(object):
@run_in_gui_thread(wait=True) @run_in_gui_thread(wait=True)
def store_file(self, id, file): def store_file(self, id, file):
id = id.replace('/', '_')
directory = ApplicationData.get('images') directory = ApplicationData.get('images')
filename = os.path.join(directory, id + '.png') filename = os.path.join(directory, id + '.png')
if filename == os.path.normpath(file): if filename == os.path.normpath(file):
...@@ -166,6 +169,7 @@ class IconManager(object): ...@@ -166,6 +169,7 @@ class IconManager(object):
@run_in_gui_thread(wait=True) @run_in_gui_thread(wait=True)
def remove(self, id): def remove(self, id):
id = id.replace('/', '_')
self.iconmap.pop(id, None) self.iconmap.pop(id, None)
unlink(ApplicationData.get(os.path.join('images', id + '.png'))) unlink(ApplicationData.get(os.path.join('images', id + '.png')))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment