Example #1
0
 def gen_used_smiley_css(self):
     ret = HEAD
     for path in self.used_smileys:
         fname = os.path.join(STATIC_PATH, path)
         b64 = get_file_b64(fname)
         ret = ret + TEMPLATE.format(name=_css_class_name(path), b64=b64)
     return ret
Example #2
0
 def gen_used_smiley_css(self):
     ret = HEAD
     for sid in self.used_smiley_id:
         fname = os.path.join(STATIC_PATH, 'smileys', '{}.png'.format(sid))
         b64 = get_file_b64(fname)
         ret = ret + TEMPLATE.format(name=sid, b64=b64)
     return ret
Example #3
0
 def get_jpg_b64(img_file):
     if not img_file:
         return None
     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)
         return base64.b64encode(buf.getvalue())
     return get_file_b64(img_file)
Example #4
0
 def get_jpg_b64(img_file):
     if not img_file:
         return None
     if not img_file.endswith('jpg') and \
        imghdr.what(img_file) != 'jpeg':
         im = Image.open(open(img_file, 'rb'))
         buf = cStringIO.StringIO()
         im.convert('RGB').save(buf, 'JPEG', quality=JPEG_QUALITY)
         return base64.b64encode(buf.getvalue())
     return get_file_b64(img_file)
Example #5
0
def do_parse_wechat_audio_file(file_name):
    """ return a mp3 base64 string, and the duration"""
    if not file_name: return "", 0

    mp3_file = os.path.join('/tmp', os.path.basename(file_name)[:-4] + '.mp3')
    with open(file_name) as f:
        header = f.read(10)
    if 'AMR' in header:
        # maybe this is faster than calling sox from command line?
        infile = pysox.CSoxStream(file_name)
        outfile = pysox.CSoxStream(mp3_file, 'w', infile.get_signal())
        chain = pysox.CEffectsChain(infile, outfile)
        chain.flow_effects()
        outfile.close()

        signal = infile.get_signal().get_signalinfo()
        duration = signal['length'] * 1.0 / signal['rate']
    elif 'SILK' in header:
        raw_file = os.path.join('/tmp',
                                os.path.basename(file_name)[:-4] + '.raw')
        proc = Popen('{0} {1} {2}'.format(SILK_DECODER, file_name, raw_file),
                     shell=True,
                     stdout=PIPE,
                     stderr=PIPE)
        stdout = proc.communicate()[0]
        for line in stdout.split('\n'):
            if 'File length' in line:
                duration = float(line[13:-3].strip())
                break
        else:
            raise RuntimeError("Error decoding silk audio file!")

        # I don't know how to do this with pysox
        proc = call('sox -r 24000 -e signed -b 16 -c 1 {} {}'.format(
            raw_file, mp3_file),
                    shell=True)
        os.unlink(raw_file)
    else:
        raise NotImplementedError("Unsupported Audio Format! This is a bug!")
    try:
        mp3_string = get_file_b64(mp3_file)
        os.unlink(mp3_file)
    except:
        raise RuntimeError("Failed to decode audio file: {}".format(file_name))
    return mp3_string, duration
Example #6
0
def do_parse_wechat_audio_file(file_name):
    """ return a mp3 base64 string, and the duration"""
    if not file_name: return "", 0

    mp3_file = os.path.join('/tmp',
                            os.path.basename(file_name)[:-4] + '.mp3')
    with open(file_name) as f:
        header = f.read(10)
    if 'AMR' in header:
        # maybe this is faster than calling sox from command line?
        infile = pysox.CSoxStream(file_name)
        outfile = pysox.CSoxStream(mp3_file, 'w', infile.get_signal())
        chain = pysox.CEffectsChain(infile, outfile)
        chain.flow_effects()
        outfile.close()

        signal = infile.get_signal().get_signalinfo()
        duration = signal['length'] * 1.0 / signal['rate']
    elif 'SILK' in header:
        raw_file = os.path.join('/tmp',
                                os.path.basename(file_name)[:-4] + '.raw')
        proc = Popen('{0} {1} {2}'.format(SILK_DECODER,
                                                file_name, raw_file),
                    shell=True, stdout=PIPE, stderr=PIPE)
        stdout = proc.communicate()[0]
        for line in stdout.split('\n'):
            if 'File length' in line:
                duration = float(line[13:-3].strip())
                break
        else:
            raise RuntimeError("Error decoding silk audio file!")

        # I don't know how to do this with pysox
        proc = call('sox -r 24000 -e signed -b 16 -c 1 {} {}'.format(
            raw_file, mp3_file), shell=True)
        os.unlink(raw_file)
    else:
        raise NotImplementedError("Unsupported Audio Format! This is a bug!")
    try:
        mp3_string = get_file_b64(mp3_file)
        os.unlink(mp3_file)
    except:
        raise RuntimeError("Failed to decode audio file: {}".format(file_name))
    return mp3_string, duration
Example #7
0
def do_parse_wechat_audio_file(file_name):
    """ return a mp3 stored in base64 unicode string, and the duration"""
    if not file_name: return "", 0

    mp3_file = os.path.join('/tmp', os.path.basename(file_name)[:-4] + '.mp3')
    with open(file_name, 'rb') as f:
        header = f.read(10)
    if b'AMR' in header:
        cmd = f"sox -e signed -c 1 {file_name} {mp3_file}"
        subproc_succ(cmd)
        cmd = f"soxi -D {mp3_file}"
        duration = float(subproc_succ(cmd))

        # The below is python2 only. It should be equivalent to using sox from command line
        # import pysox
        # infile = pysox.CSoxStream(file_name)
        # outfile = pysox.CSoxStream(mp3_file, 'w', infile.get_signal())
        # chain = pysox.CEffectsChain(infile, outfile)
        # chain.flow_effects()
        # outfile.close()
        # signal = infile.get_signal().get_signalinfo()
        # duration = signal['length'] * 1.0 / signal['rate']
    elif b'SILK' in header:
        raw_file = os.path.join('/tmp',
                                os.path.basename(file_name)[:-4] + '.raw')
        cmd = '{0} {1} {2}'.format(SILK_DECODER, file_name, raw_file)
        out = subproc_succ(cmd)
        for line in out.split(b'\n'):
            if b'File length' in line:
                duration = float(line[13:-3].strip())
                break
        else:
            raise RuntimeError("Error decoding silk audio file!")

        # TODO don't know how to do this with python
        subproc_succ('sox -r 24000 -e signed -b 16 -c 1 {} {}'.format(
            raw_file, mp3_file))
        os.unlink(raw_file)
    else:
        raise NotImplementedError("Audio file format cannot be recognized.")
    mp3_string = get_file_b64(mp3_file)
    os.unlink(mp3_file)
    return mp3_string, duration
Example #8
0
 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)]
         # only one file is the gif in need, others are frames or cover
         if len(candidates) == 0:
             # TODO stitch frames to gif
             logger.warning("Cannot find emoji: {}".format(md5))
             return None, None
     if not candidates:
         return None, None
     fname = candidates[0]
     return get_file_b64(fname), imghdr.what(fname)
Example #9
0
 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)
         ]
         # only one file is the gif in need, others are frames or cover
         if len(candidates) == 0:
             # TODO stitch frames to gif
             logger.warning("Cannot find emoji: {}".format(md5))
             return None, None
     if not candidates:
         return None, None
     fname = candidates[0]
     return get_file_b64(fname), imghdr.what(fname)
Example #10
0
    def _get_res_emoji(self, md5, pack_id, allow_cover=False):
        """
        pack_id: can be None
        allow_cover: Cover is non-animated. Can be used as a fallback.
        """
        path = os.path.join(self.emoji_dir, pack_id or '')
        candidates = glob.glob(os.path.join(path, '{}*'.format(md5)))
        candidates = [k for k in candidates if not k.endswith('_thumb') \
                and not re.match('.*_[0-9]+$', k)]

        def try_use(f):
            if not f: return None
            if not imghdr.what(f[0]):   # cannot recognize file type
                return None
            return f[0]

        candidates = [k for k in candidates if (allow_cover or not k.endswith('_cover'))]

        for cand in candidates:
            if imghdr.what(cand):
                return get_file_b64(cand), imghdr.what(cand)
        return None, None
Example #11
0
    def _get_res_emoji(self, md5, pack_id, allow_cover=False):
        """
        pack_id: can be None
        allow_cover: Cover is non-animated. Can be used as a fallback.
        """
        path = os.path.join(self.emoji_dir, pack_id or '')
        candidates = glob.glob(os.path.join(path, '{}*'.format(md5)))
        candidates = [k for k in candidates if not k.endswith('_thumb') \
                and not re.match('.*_[0-9]+$', k)]

        def try_use(f):
            if not f: return None
            if not imghdr.what(f[0]):   # cannot recognize file type
                return None
            return f[0]

        candidates = [k for k in candidates if (allow_cover or not k.endswith('_cover'))]

        for cand in candidates:
            if imghdr.what(cand):
                return get_file_b64(cand), imghdr.what(cand)
        return None, None
Example #12
0
    def _get_res_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 re.match('.*_[0-9]+$', k)]

        def try_use(f):
            if not f: return None
            if not imghdr.what(f[0]):   # cannot recognize file type
                return None
            return f[0]

        f = try_use([k for k in candidates if not k.endswith('_cover')])
        if f:
            return get_file_b64(f), imghdr.what(f)

        # don't try do use cover anymore. cover is not animated
        #f = try_use([k for k in candidates if k.endswith('_cover')])
        #if f:
            #return get_file_b64(f), imghdr.what(f)
        return None, None
Example #13
0
    def _get_res_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 re.match('.*_[0-9]+$', k)]

        def try_use(f):
            if not f: return None
            if not imghdr.what(f[0]):   # cannot recognize file type
                return None
            return f[0]

        f = try_use([k for k in candidates if not k.endswith('_cover')])
        if f:
            return get_file_b64(f), imghdr.what(f)

        # don't try do use cover anymore. cover is not animated
        #f = try_use([k for k in candidates if k.endswith('_cover')])
        #if f:
            #return get_file_b64(f), imghdr.what(f)
        return None, None
Example #14
0
    def render_msg(self, msg):
        """ render a message, return the html block"""
        # TODO for chatroom, add nickname on avatar
        sender = u'you ' + msg.talker if not msg.isSend else 'me'
        format_dict = {'sender_label': sender, 'time': msg.createTime}
        if (not msg.isSend and msg.is_chatroom()):
            format_dict[
                'nickname'] = '>\n       <pre align=\'left\'>' + msg.talker_nickname + '</pre'
        else:
            format_dict['nickname'] = ' '

        def fallback():
            template = TEMPLATES[TYPE_MSG]
            content = msg.msg_str()
            format_dict['content'] = self.smiley.replace_smileycode(content)
            return template.format(**format_dict)

        template = TEMPLATES.get(msg.type)
        if msg.type == TYPE_SPEAK:
            audio_str, duration = self.res.get_voice_mp3(msg.imgPath)
            format_dict['voice_duration'] = duration
            format_dict['voice_str'] = audio_str
            return template.format(**format_dict)
        elif msg.type == TYPE_IMG:
            # imgPath was original THUMBNAIL_DIRPATH://th_xxxxxxxxx
            imgpath = msg.imgPath.split('_')[-1]
            if not imgpath:
                logger.warn(
                    'No imgpath in an image message. Perhaps a bug in wechat.')
                return fallback()
            bigimgpath = self.parser.imginfo.get(msg.msgSvrId)
            fnames = [k for k in [imgpath, bigimgpath] if k]
            img = self.res.get_img(fnames)
            if not img:
                logger.warn("No image thumbnail found for {}".format(imgpath))
                return fallback()
            # TODO do not show fancybox when no bigimg found
            format_dict['img'] = (img, 'jpeg')
            return template.format(**format_dict)
        elif msg.type == TYPE_EMOJI or msg.type == TYPE_CUSTOM_EMOJI:
            if 'emoticonmd5' in msg.content:
                pq = PyQuery(msg.content)
                md5 = pq('emoticonmd5').text()
            else:
                md5 = msg.imgPath
                # TODO md5 could exist in both.
                # first is emoji md5, second is image2/ md5
                # can use fallback here.
            if md5:
                emoji_img, format = self.res.get_emoji_by_md5(md5)
                format_dict['emoji_format'] = format
                format_dict['emoji_img'] = emoji_img
            else:
                import IPython as IP
                IP.embed()
            return template.format(**format_dict)
        elif msg.type == TYPE_LINK:
            content = msg.msg_str()
            # TODO show a short link with long href, if link too long
            if content.startswith(u'URL:'):
                url = content[4:]
                content = u'URL:<a target="_blank" href="{0}">{0}</a>'.format(
                    url)
                format_dict['content'] = content
                return template.format(**format_dict)
        elif msg.type == TYPE_VIDEO_FILE:
            video = self.res.get_video(msg.imgPath)
            if video.endswith(".mp4"):
                video_str = get_file_b64(video)
                format_dict["video_str"] = video_str
                return template.format(**format_dict)
            elif video.endswith(".jpg"):
                # only has thumbnail
                image_str = get_file_b64(video)
                format_dict["img"] = (image_str, 'jpeg')
                return TEMPLATES[TYPE_IMG].format(**format_dict)
            return f"VIDEO FILE {msg.imgPath}"
        elif msg.type == TYPE_WX_VIDEO:
            # TODO: fetch video from resource
            return fallback()
        return fallback()
Example #15
0
 def _get_internal_emoji(self, fname):
     f = os.path.join(INTERNAL_EMOJI_DIR, fname)
     return get_file_b64(f), imghdr.what(f)
Example #16
0
def parse_wechat_video_file(path):
    return get_file_b64(path), duration(path)
Example #17
0
 def get_internal_emoji(self, fname):
     f = os.path.join(INTERNAL_EMOJI_DIR, fname)
     return get_file_b64(f), imghdr.what(f)