Download whatsapp profile pictures

Everytime the user requests a VCard the profile pictures are updated.
The sha1hash hash of the picture is calculated and stored in buddy.
This commit is contained in:
moyamo 2015-09-06 00:14:12 +02:00
parent d2efa0dd7b
commit 4fd313e516
6 changed files with 55 additions and 20 deletions

View file

@ -48,7 +48,7 @@ class Number():
class Buddy(): class Buddy():
def __init__(self, owner, number, nick, groups, id, db): def __init__(self, owner, number, nick, groups, image_hash, id, db):
self.id = id self.id = id
self.db = db self.db = db
@ -56,14 +56,16 @@ class Buddy():
self.owner = owner self.owner = owner
self.number = number self.number = number
self.groups = groups self.groups = groups
self.image_hash = image_hash
def update(self, nick, groups): def update(self, nick, groups, image_hash):
self.nick = nick self.nick = nick
self.groups = groups self.groups = groups
self.image_hash = image_hash
groups = u",".join(groups).encode("latin-1") groups = u",".join(groups).encode("latin-1")
cur = self.db.cursor() cur = self.db.cursor()
cur.execute("UPDATE buddies SET nick = %s, groups = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, groups, self.owner.id, self.number.id)) cur.execute("UPDATE buddies SET nick = %s, groups = %s, image_hash = %s WHERE owner_id = %s AND buddy_id = %s", (self.nick, groups, image_hash, self.owner.id, self.number.id))
self.db.commit() self.db.commit()
def delete(self): def delete(self):
@ -73,13 +75,13 @@ class Buddy():
self.id = None self.id = None
@staticmethod @staticmethod
def create(owner, number, nick, groups, db): def create(owner, number, nick, groups, image_hash, db):
groups = u",".join(groups).encode("latin-1") groups = u",".join(groups).encode("latin-1")
cur = db.cursor() cur = db.cursor()
cur.execute("REPLACE buddies (owner_id, buddy_id, nick, groups) VALUES (%s, %s, %s, %s)", (owner.id, number.id, nick, groups)) cur.execute("REPLACE buddies (owner_id, buddy_id, nick, groups, image_hash) VALUES (%s, %s, %s, %s, %s)", (owner.id, number.id, nick, groups, image_hash))
db.commit() db.commit()
return Buddy(owner, number, nick, groups, cur.lastrowid, db) return Buddy(owner, number, nick, groups, image_hash, cur.lastrowid, db)
def __str__(self): def __str__(self):
return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id) return "%s (nick=%s, id=%s)" % (self.number, self.nick, self.id)
@ -99,7 +101,8 @@ class BuddyList(dict):
n.number AS number, n.number AS number,
b.nick AS nick, b.nick AS nick,
b.groups AS groups, b.groups AS groups,
n.state AS state n.state AS state,
b.image_hash AS image_hash
FROM buddies AS b FROM buddies AS b
LEFT JOIN numbers AS n LEFT JOIN numbers AS n
ON b.buddy_id = n.id ON b.buddy_id = n.id
@ -109,20 +112,20 @@ class BuddyList(dict):
ORDER BY b.owner_id DESC""", self.owner.id) ORDER BY b.owner_id DESC""", self.owner.id)
for i in range(cur.rowcount): for i in range(cur.rowcount):
id, number, nick, groups, state = cur.fetchone() id, number, nick, groups, state, image_hash = cur.fetchone()
self[number] = Buddy(self.owner, Number(number, state, self.db), nick.decode('latin1'), groups.split(","), id, self.db) self[number] = Buddy(self.owner, Number(number, state, self.db), nick.decode('latin1'), groups.split(","), image_hash, id, self.db)
def update(self, number, nick, groups): def update(self, number, nick, groups, image_hash):
if number in self: if number in self:
buddy = self[number] buddy = self[number]
buddy.update(nick, groups) buddy.update(nick, groups, image_hash)
else: else:
buddy = self.add(number, nick, groups, 1) buddy = self.add(number, nick, groups, 1, image_hash)
return buddy return buddy
def add(self, number, nick, groups = [], state = 0): def add(self, number, nick, groups = [], state = 0, image_hash = ""):
return Buddy.create(self.owner, Number(number, state, self.db), nick, groups, self.db) return Buddy.create(self.owner, Number(number, state, self.db), nick, groups, image_hash, self.db)
def remove(self, number): def remove(self, number):
try: try:

View file

@ -13,6 +13,7 @@ CREATE TABLE IF NOT EXISTS `buddies` (
`buddy_id` int(11) NOT NULL, `buddy_id` int(11) NOT NULL,
`nick` varchar(255) NOT NULL, `nick` varchar(255) NOT NULL,
`groups` varchar(255) NOT NULL, `groups` varchar(255) NOT NULL,
`image_hash` varchar(40),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View file

@ -110,6 +110,7 @@ class Session(YowsupApp):
for number in add: for number in add:
buddy = self.buddies[number] buddy = self.buddies[number]
self.subscribePresence(number) self.subscribePresence(number)
self.backend.handleBuddyChanged(self.user, number, buddy.nick, buddy.groups, protocol_pb2.STATUS_NONE, iconHash = buddy.image_hash if buddy.image_hash is not None else "")
self.requestLastSeen(number, self._lastSeen) self.requestLastSeen(number, self._lastSeen)
def _lastSeen(self, number, seconds): def _lastSeen(self, number, seconds):
@ -368,9 +369,9 @@ class Session(YowsupApp):
self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2]) self.backend.handleMessage(self.user, msg[0], msg[1], "", "", msg[2])
# also for adding a new buddy # also for adding a new buddy
def updateBuddy(self, buddy, nick, groups): def updateBuddy(self, buddy, nick, groups, image_hash =""):
if buddy != "bot": if buddy != "bot":
self.buddies.update(buddy, nick, groups) self.buddies.update(buddy, nick, groups, image_hash)
self.updateRoster() self.updateRoster()
def removeBuddy(self, buddy): def removeBuddy(self, buddy):
@ -391,6 +392,20 @@ class Session(YowsupApp):
self.backend.handleSubject(self.user, room, group.subject, group.subjectOwner) self.backend.handleSubject(self.user, room, group.subject, group.subjectOwner)
else: else:
self.logger.warn("Room doesn't exist: %s", room) self.logger.warn("Room doesn't exist: %s", room)
def requestVCard(self, buddy, ID):
def onSuccess(response, request):
self.logger.debug('Sending VCard (%s) with image id %s',
ID, response.pictureId)
image_hash = utils.sha1hash(response.pictureData)
self.logger.debug('Image hash is %s', image_hash)
self.backend.handleVCard(self.user, ID, buddy, "", "", response.pictureData)
obuddy = self.buddies[buddy]
self.updateBuddy(buddy, obuddy.nick, obuddy.groups, image_hash)
self.logger.debug('Requesting profile picture of %s', buddy)
self.requestProfilePicture(buddy, onSuccess = onSuccess)
# Not used # Not used
def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast): def onLocationReceived(self, messageId, jid, name, preview, latitude, longitude, receiptRequested, isBroadcast):

View file

@ -26,6 +26,7 @@ import urllib
import json import json
import e4u import e4u
import base64 import base64
import hashlib
def shorten(url): def shorten(url):
url = urllib.urlopen("http://d.0l.de/add.json?type=URL&rdata=%s" % urllib.quote(url)) url = urllib.urlopen("http://d.0l.de/add.json?type=URL&rdata=%s" % urllib.quote(url))
@ -61,3 +62,6 @@ def softToUni(message):
def decodePassword(password): def decodePassword(password):
return base64.b64decode(bytes(password.encode("utf-8"))) return base64.b64decode(bytes(password.encode("utf-8")))
def sha1hash(data):
return hashlib.sha1(data).hexdigest()

View file

@ -101,6 +101,10 @@ class WhatsAppBackend(SpectrumBackend):
self.logger.debug("handleStoppedTypingRequest(user=%s, buddy=%s)", user, buddy) self.logger.debug("handleStoppedTypingRequest(user=%s, buddy=%s)", user, buddy)
self.sessions[user].sendTypingStopped(buddy) self.sessions[user].sendTypingStopped(buddy)
def handleVCardRequest(self, user, buddy, ID):
self.logger.debug("handleVCardRequest(user=%s, buddy=%s, ID=%s)", user, buddy, ID)
self.sessions[user].requestVCard(buddy, ID)
# TODO # TODO
def handleBuddyBlockToggled(self, user, buddy, blocked): def handleBuddyBlockToggled(self, user, buddy, blocked):
pass pass
@ -108,9 +112,6 @@ class WhatsAppBackend(SpectrumBackend):
def handleLeaveRoomRequest(self, user, room): def handleLeaveRoomRequest(self, user, room):
pass pass
def handleVCardRequest(self, user, buddy, ID):
pass
def handleVCardUpdatedRequest(self, user, photo, nickname): def handleVCardUpdatedRequest(self, user, photo, nickname):
pass pass

View file

@ -206,13 +206,24 @@ class YowsupApp(object):
- failure: (func) called when request has failed - failure: (func) called when request has failed
""" """
iq = LastseenIqProtocolEntity(phoneNumber + '@s.whatsapp.net') iq = LastseenIqProtocolEntity(phoneNumber + '@s.whatsapp.net')
self.sendIq(iq, self._lastSeenSuccess(success), failure) self.sendIq(iq, onSuccess = self._lastSeenSuccess(success), onError = failure)
def _lastSeenSuccess(self, success): def _lastSeenSuccess(self, success):
def func(response, request): def func(response, request):
success(response._from.split('@')[0], response.seconds) success(response._from.split('@')[0], response.seconds)
return func return func
def requestProfilePicture(self, phoneNumber, onSuccess = None, onFailure = None):
"""
Requests profile picture of whatsapp user
Args:
- phoneNumber: (str) the phone number of the user
- success: (func) called when request is successfully processed.
- failure: (func) called when request has failed
"""
iq = GetPictureIqProtocolEntity(phoneNumber + '@s.whatsapp.net')
self.sendIq(iq, onSuccess = onSuccess, onError = onFailure)
def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t): def onAuthSuccess(self, status, kind, creation, expiration, props, nonce, t):
""" """
Called when login is successful. Called when login is successful.