emoji works

This commit is contained in:
ppwwyyxx
2014-12-20 20:30:46 +08:00
parent e970fa2fb5
commit 337c1f8acf
6 changed files with 62 additions and 17 deletions
+3 -1
View File
@@ -37,6 +37,8 @@
```
### TODO
+ Parse custom emoji, and other message types
+ Parse uncommon message types
+ Show name of emoji in text
+ Search by uid/username..
+ Fix emoji sizes..
+ Sometimes beautiful soup failed on links..
+12 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
# File: msg.py
# Date: Sat Dec 20 15:12:34 2014 +0800
# Date: Sat Dec 20 18:38:59 2014 +0800
# Author: Yuxin Wu <[email protected]>
from datetime import datetime
@@ -77,6 +77,9 @@ class WeChatMsg(object):
if not name:
name = msg.get('alias', '')
return u"NAMECARD: {}".format(name)
elif self.type == TYPE_EMOJI:
# TODO add emoji name
return self.content
else:
return self.content
@@ -95,3 +98,11 @@ class WeChatMsg(object):
def __lt__(self, r):
return self.createTime < r.createTime
def get_emoji_product_id(self):
assert self.type == TYPE_EMOJI, "Wrong call to get_emoji_product_id()!"
soup = BeautifulSoup(self.content)
emoji = soup.find('emoji')
if emoji is None:
return None
return emoji.get('productid', None)
+11 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
# File: parser.py
# Date: Sat Dec 20 15:58:16 2014 +0800
# Date: Sat Dec 20 19:40:31 2014 +0800
# Author: Yuxin Wu <[email protected]>
import sqlite3
@@ -30,6 +30,7 @@ class WeChatDBParser(object):
self.cc = self.db_conn.cursor()
self.contacts = {}
self.msgs_by_talker = defaultdict(list)
self.emojis = {}
self.parse()
def _parse_contact(self):
@@ -86,8 +87,17 @@ SELECT {} FROM message
ret.append(msg)
return sorted(ret)
def _parse_emoji(self):
# wechat provided emojis
emojiinfo_q = self.cc.execute(
""" SELECT md5, desc, groupid FROM EmojiInfoDesc """)
for row in emojiinfo_q:
md5, desc, group = row
self.emojis[md5] = (group, desc)
def parse(self):
self._parse_userinfo()
self._parse_contact()
self._parse_msg()
self._parse_imginfo()
self._parse_emoji()
+11 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
# File: render.py
# Date: Sat Dec 20 17:48:48 2014 +0800
# Date: Sat Dec 20 20:15:47 2014 +0800
# Author: Yuxin Wu <[email protected]>
import os
@@ -24,7 +24,8 @@ from smiley import SmileyProvider
TEMPLATES_FILES = {TYPE_MSG: "TP_MSG",
TYPE_IMG: "TP_IMG",
TYPE_SPEAK: "TP_SPEAK"}
TYPE_SPEAK: "TP_SPEAK",
TYPE_EMOJI: "TP_EMOJI"}
TEMPLATES = dict([(k, open(os.path.join(
LIB_PATH, 'static/{}.html'.format(v))).read())
for k, v in TEMPLATES_FILES.iteritems()])
@@ -96,10 +97,15 @@ class HTMLRender(object):
big_img=bigimg)
elif msg.type == TYPE_EMOJI:
imgpath = msg.imgPath
print imgpath
return fallback()
# custom emoji
if imgpath in self.parser.emojis:
group, _ = self.parser.emojis[imgpath]
else:
group = None
emoji_img, format = self.res.get_emoji(imgpath, group)
return template.format(sender_label=sender,
emoji_format=format,
emoji_img=emoji_img)
return fallback()
def render_msgs(self, msgs):
+25 -6
View File
@@ -1,22 +1,26 @@
#!/usr/bin/env python2
# -*- coding: UTF-8 -*-
# File: res.py
# Date: Sat Dec 20 16:26:51 2014 +0800
# Date: Sat Dec 20 20:14:40 2014 +0800
# Author: Yuxin Wu <[email protected]>
import glob
import os
import re
import Image
import cStringIO
import base64
import logging
import eyed3
import imghdr
logger = logging.getLogger(__name__)
import eyed3
from lib.avatar import AvatarReader
VOICE_DIRNAME = 'voice2'
IMG_DIRNAME = 'image2'
EMOJI_DIRNAME = 'emoji'
JPEG_QUALITY = 50
class Resource(object):
@@ -25,6 +29,7 @@ class Resource(object):
assert os.path.isdir(res_dir), "No such directory: {}".format(res_dir)
self.res_dir = res_dir
self.img_dir = os.path.join(res_dir, IMG_DIRNAME)
self.emoji_dir = os.path.join(res_dir, EMOJI_DIRNAME)
assert os.path.isdir(self.img_dir), \
"No such directory: {}".format(self.img_dir)
self.avt_reader = AvatarReader(self.res_dir)
@@ -78,7 +83,7 @@ class Resource(object):
jpeg_str = buf.getvalue()
return base64.b64encode(jpeg_str)
def get_img_file(self, fnames):
def _get_img_file(self, fnames):
""" fnames: a list of filename to search for
return (filename, filename) of (big, small) image.
could be empty string.
@@ -120,13 +125,13 @@ class Resource(object):
def get_img(self, fnames):
""" return two base64 jpg string"""
big_file, small_file = self.get_img_file(fnames)
big_file, small_file = self._get_img_file(fnames)
def get_jpg_b64(img_file):
if not img_file:
return None
if not img_file.endswith('jpg'):
# possibly not jpg
if not img_file.endswith('jpg') and \
imghdr.what(img_file) != 'jpeg':
im = Image.open(open(img_file, 'rb'))
buf = cStringIO.StringIO()
im.save(buf, 'JPEG', quality=JPEG_QUALITY)
@@ -140,3 +145,17 @@ class Resource(object):
pass
return (big_file, small_file)
def get_emoji(self, md5, pack_id):
path = self.emoji_dir
if pack_id:
path = os.path.join(path, pack_id)
candidates = glob.glob(os.path.join(path, '{}*'.format(md5)))
candidates = [k for k in candidates if \
not k.endswith('_thumb') and not k.endswith('_cover')]
if len(candidates) > 1:
# annimation
candidates = [k for k in candidates if not re.match('.*_[0-9]+$', k)]
assert len(candidates) == 1
fname = candidates[0]
return Resource.get_file_b64(fname), imghdr.what(fname)
-3
View File
@@ -5242,7 +5242,6 @@ a.btnBlue:active .btnBluePanel {
}
.cloudImg .cloudContent {
min-height: 30px;
max-height: 200px;
}
.cloudImg .cloudContent img {
min-width: 50px;
@@ -5447,8 +5446,6 @@ a.btnBlue:active .btnBluePanel {
}
.you .cloudImg .img_wrap{
display: block;
max-width: 280px;
max-height: 150px;
overflow: hidden;
}
.you .cloudImg .cloudArrow {