|
|
@@ -1,3 +1,4 @@
|
|
|
+#!/usr/bin/env python3
|
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
|
|
from PIL import Image
|
|
|
@@ -35,32 +36,36 @@ class AvatarReader(object):
|
|
|
""" username: `username` field in db.rcontact"""
|
|
|
if not self._use_avt:
|
|
|
return None
|
|
|
+ username = ensure_unicode(username)
|
|
|
+ avtid = md5(username.encode('utf-8'))
|
|
|
+ dir1, dir2 = avtid[:2], avtid[2:4]
|
|
|
+ candidates = glob.glob(os.path.join(self.avt_dir, dir1, dir2, f"*{avtid}*"))
|
|
|
+ default_candidate = os.path.join(self.avt_dir, dir1, dir2, f"user_{avtid}.png")
|
|
|
+ candidates.append(default_candidate)
|
|
|
|
|
|
- username = ensure_unicode(username).encode('utf-8')
|
|
|
- filename = md5(username)
|
|
|
- dir1, dir2 = filename[:2], filename[2:4]
|
|
|
- filename = os.path.join(dir1, dir2,
|
|
|
- "user_{}.png".format(filename))
|
|
|
+ def priority(s):
|
|
|
+ if "_hd" in s and s.endswith(".png"):
|
|
|
+ return 10
|
|
|
+ else:
|
|
|
+ return 1
|
|
|
|
|
|
- try:
|
|
|
+ candidates = sorted(set(candidates), key=priority, reverse=True)
|
|
|
+
|
|
|
+ for cand in candidates:
|
|
|
try:
|
|
|
if self.avt_use_db:
|
|
|
- pos, size = self.query_index(filename)
|
|
|
+ pos, size = self.query_index(cand)
|
|
|
return self.read_img(pos, size)
|
|
|
else:
|
|
|
- img_file = os.path.join(self.avt_dir, filename)
|
|
|
- if os.path.exists(img_file):
|
|
|
- return Image.open(img_file)
|
|
|
- else:
|
|
|
- return None
|
|
|
- except TypeError:
|
|
|
- logger.warning("Avatar for {} not found in avatar database.".format(username))
|
|
|
- return None
|
|
|
- except Exception as e:
|
|
|
- raise
|
|
|
- # logger.exception("Failed to retrieve avatar!")
|
|
|
- # return None
|
|
|
-
|
|
|
+ if os.path.exists(cand):
|
|
|
+ if cand.endswith(".bm"):
|
|
|
+ return self.read_bm_file(cand)
|
|
|
+ else:
|
|
|
+ return Image.open(cand)
|
|
|
+ except Exception:
|
|
|
+ logger.exception("HHH")
|
|
|
+ pass
|
|
|
+ logger.warning("Avatar for {} not found in avatar database.".format(username))
|
|
|
|
|
|
def read_img(self, pos, size):
|
|
|
file_idx = pos >> 32
|
|
|
@@ -78,8 +83,25 @@ class AvatarReader(object):
|
|
|
logger.warn("Cannot read avatar from {}: {}".format(fname, str(e)))
|
|
|
return None
|
|
|
|
|
|
+ def read_bm_file(self, fname):
|
|
|
+ # history at https://github.com/ppwwyyxx/wechat-dump/pull/14
|
|
|
+ with open(fname, 'rb') as f:
|
|
|
+ # filesize is 36880=96x96x4+16
|
|
|
+ size = (96, 96, 3)
|
|
|
+ img = np.zeros(size, dtype='uint8')
|
|
|
+ for i in range(96):
|
|
|
+ for j in range(96):
|
|
|
+ r, g, b, a = f.read(4)
|
|
|
+ img[i,j] = (r, g, b)
|
|
|
+ return Image.fromarray(img, mode="RGB")
|
|
|
+
|
|
|
def query_index(self, filename):
|
|
|
conn = sqlite3.connect(self.avt_db)
|
|
|
cursor = conn.execute("select Offset,Size from Index_avatar where FileName='{}'".format(filename))
|
|
|
pos, size = cursor.fetchone()
|
|
|
return pos, size
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ import sys
|
|
|
+ r = AvatarReader(sys.argv[1], sys.argv[2])
|
|
|
+ print(r.get_avatar(sys.argv[3]))
|