def upload_file(self, fileDir, isPicture=False, isVideo=False, toUserName='******', file_=None, preparedFile=None): logger.debug('Request to upload a %s: %s' % ( 'picture' if isPicture else 'video' if isVideo else 'file', fileDir)) if not preparedFile: preparedFile = _prepare_file(fileDir, file_) if not preparedFile: return preparedFile fileSize, fileMd5, file_ = \ preparedFile['fileSize'], preparedFile['fileMd5'], preparedFile['file_'] fileSymbol = 'pic' if isPicture else 'video' if isVideo else'doc' chunks = int((fileSize - 1) / 524288) + 1 clientMediaId = int(time.time() * 1e4) uploadMediaRequest = json.dumps(OrderedDict([ ('UploadType', 2), ('BaseRequest', self.loginInfo['BaseRequest']), ('ClientMediaId', clientMediaId), ('TotalLen', fileSize), ('StartPos', 0), ('DataLen', fileSize), ('MediaType', 4), ('FromUserName', self.storageClass.userName), ('ToUserName', toUserName), ('FileMd5', fileMd5)] ), separators = (',', ':')) r = {'BaseResponse': {'Ret': -1005, 'ErrMsg': 'Empty file detected'}} for chunk in range(chunks): r = upload_chunk_file(self, fileDir, fileSymbol, fileSize, file_, chunk, chunks, uploadMediaRequest) file_.close() if isinstance(r, dict): return ReturnValue(r) return ReturnValue(rawResponse=r)
def get_head_img(self, userName=None, chatroomUserName=None, picDir=None): ''' get head image * if you want to get chatroom header: only set chatroomUserName * if you want to get friend header: only set userName * if you want to get chatroom member header: set both ''' params = { 'userName': userName or chatroomUserName or self.storageClass.userName, 'skey': self.loginInfo['skey'], 'type': 'big', } url = '%s/webwxgeticon' % self.loginInfo['url'] if chatroomUserName is None: infoDict = self.storageClass.search_friends(userName=userName) if infoDict is None: return ReturnValue({ 'BaseResponse': { 'ErrMsg': 'No friend found', 'Ret': -1001, } }) else: if userName is None: url = '%s/webwxgetheadimg' % self.loginInfo['url'] else: chatroom = self.storageClass.search_chatrooms( userName=chatroomUserName) if chatroomUserName is None: return ReturnValue({ 'BaseResponse': { 'ErrMsg': 'No chatroom found', 'Ret': -1001, } }) if 'EncryChatRoomId' in chatroom: params['chatroomid'] = chatroom['EncryChatRoomId'] params['chatroomid'] = params['chatroomid'] or chatroom['UserName'] headers = {'User-Agent': config.USER_AGENT} r = self.s.get(url, params=params, stream=True, headers=headers) tempStorage = io.BytesIO() for block in r.iter_content(1024): tempStorage.write(block) if picDir is None: return tempStorage.getvalue() with open(picDir, 'wb') as f: f.write(tempStorage.getvalue()) tempStorage.seek(0) return ReturnValue({ 'BaseResponse': { 'ErrMsg': 'Successfully downloaded', 'Ret': 0, }, 'PostFix': utils.get_image_postfix(tempStorage.read(20)), })
def load_login_status(self, fileDir, loginCallback=None, exitCallback=None): try: with open(fileDir, 'rb') as f: j = pickle.load(f) except Exception as e: logger.debug('No such file, loading login status failed.') return ReturnValue({'BaseResponse': { 'ErrMsg': 'No such file, loading login status failed.', 'Ret': -1002, }}) if j.get('version', '') != VERSION: logger.debug(('you have updated itchat from %s to %s, ' + 'so cached status is ignored') % ( j.get('version', 'old version'), VERSION)) return ReturnValue({'BaseResponse': { 'ErrMsg': 'cached status ignored because of version', 'Ret': -1005, }}) self.loginInfo = j['loginInfo'] self.loginInfo['User'] = templates.User(self.loginInfo['User']) self.loginInfo['User'].core = self self.s.cookies = requests.utils.cookiejar_from_dict(j['cookies']) self.storageClass.loads(j['storage']) try: msgList, contactList = self.get_msg() except: msgList = contactList = None if (msgList or contactList) is None: self.logout() load_last_login_status(self.s, j['cookies']) logger.debug('server refused, loading login status failed.') return ReturnValue({'BaseResponse': { 'ErrMsg': 'server refused, loading login status failed.', 'Ret': -1003, }}) else: if contactList: for contact in contactList: if '@@' in contact['UserName']: update_local_chatrooms(self, [contact]) else: update_local_friends(self, [contact]) if msgList: msgList = produce_msg(self, msgList) for msg in msgList: self.msgList.put(msg) self.start_receiving(exitCallback) logger.debug('loading login status succeeded.') if hasattr(loginCallback, '__call__'): loginCallback() return ReturnValue({'BaseResponse': { 'ErrMsg': 'loading login status succeeded.', 'Ret': 0, }})
def send(self, msg, toUserName=None, mediaId=None): if not msg: r = ReturnValue({'BaseResponse': { 'ErrMsg': 'No message.', 'Ret': -1005, }}) elif msg[:5] == '@fil@': if mediaId is None: r = self.send_file(msg[5:], toUserName) else: r = self.send_file(msg[5:], toUserName, mediaId) elif msg[:5] == '@img@': if mediaId is None: r = self.send_image(msg[5:], toUserName) else: r = self.send_image(msg[5:], toUserName, mediaId) elif msg[:5] == '@msg@': r = self.send_msg(msg[5:], toUserName) elif msg[:5] == '@vid@': if mediaId is None: r = self.send_video(msg[5:], toUserName) else: r = self.send_video(msg[5:], toUserName, mediaId) else: r = self.send_msg(msg, toUserName) return r
def add_friend(self, userName, status=2, verifyContent='', autoUpdate=True): ''' Add a friend or accept a friend * for adding status should be 2 * for accepting status should be 3 ''' url = '%s/webwxverifyuser?r=%s&pass_ticket=%s' % ( self.loginInfo['url'], int(time.time()), self.loginInfo['pass_ticket']) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Opcode': status, # 3 'VerifyUserListSize': 1, 'VerifyUserList': [{ 'Value': userName, 'VerifyUserTicket': '', }], 'VerifyContent': verifyContent, 'SceneListCount': 1, 'SceneList': [33], 'skey': self.loginInfo['skey'], } headers = { 'ContentType': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode( 'utf8', 'replace')) if autoUpdate: self.update_friend(userName) return ReturnValue(rawResponse=r)
def add_member_into_chatroom(self, chatroomUserName, memberList, useInvitation=False): ''' add or invite member into chatroom * there are two ways to get members into chatroom: invite or directly add * but for chatrooms with more than 40 users, you can only use invite * but don't worry we will auto-force userInvitation for you when necessary ''' if not useInvitation: chatroom = self.storageClass.search_chatrooms( userName=chatroomUserName) if not chatroom: chatroom = self.update_chatroom(chatroomUserName) if len(chatroom['MemberList']) > self.loginInfo['InviteStartCount']: useInvitation = True if useInvitation: fun, memberKeyName = 'invitemember', 'InviteMemberList' else: fun, memberKeyName = 'addmember', 'AddMemberList' url = '%s/webwxupdatechatroom?fun=%s&pass_ticket=%s' % ( self.loginInfo['url'], fun, self.loginInfo['pass_ticket']) params = { 'BaseRequest': self.loginInfo['BaseRequest'], 'ChatRoomName': chatroomUserName, memberKeyName: ','.join([member['UserName'] for member in memberList]), } headers = { 'content-type': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT } r = self.s.post(url, data=json.dumps(params), headers=headers) return ReturnValue(rawResponse=r)
def search_member(self, name=None, userName=None, remarkName=None, nickName=None, wechatAccount=None): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s do not have members' % \ self.__class__.__name__, }, })
def _prepare_file(fileDir, file_=None): fileDict = {} if file_: if hasattr(file_, 'read'): file_ = file_.read() else: return ReturnValue({'BaseResponse': { 'ErrMsg': 'file_ param should be opened file', 'Ret': -1005, }}) else: if not utils.check_file(fileDir): return ReturnValue({'BaseResponse': { 'ErrMsg': 'No file found in specific dir', 'Ret': -1002, }}) with open(fileDir, 'rb') as f: file_ = f.read() fileDict['fileSize'] = len(file_) fileDict['fileMd5'] = hashlib.md5(file_).hexdigest() fileDict['file_'] = io.BytesIO(file_) return fileDict
def send_image(self, fileDir=None, toUserName=None, mediaId=None, file_=None): logger.debug('Request to send a image(mediaId: %s) to %s: %s' % ( mediaId, toUserName, fileDir)) if fileDir or file_: if hasattr(fileDir, 'read'): file_, fileDir = fileDir, None if fileDir is None: fileDir = 'tmp.jpg' # specific fileDir to send gifs else: return ReturnValue({'BaseResponse': { 'ErrMsg': 'Either fileDir or file_ should be specific', 'Ret': -1005, }}) if toUserName is None: toUserName = self.storageClass.userName if mediaId is None: r = self.upload_file(fileDir, isPicture=not fileDir[-4:] == '.gif', file_=file_) if r: mediaId = r['MediaId'] else: return r url = '%s/webwxsendmsgimg?fun=async&f=json' % self.loginInfo['url'] data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Msg': { 'Type': 3, 'MediaId': mediaId, 'FromUserName': self.storageClass.userName, 'ToUserName': toUserName, 'LocalID': int(time.time() * 1e4), 'ClientMsgId': int(time.time() * 1e4), }, 'Scene': 0, } if fileDir[-4:] == '.gif': url = '%s/webwxsendemoticon?fun=sys' % self.loginInfo['url'] data['Msg']['Type'] = 47 data['Msg']['EmojiFlag'] = 2 headers = { 'User-Agent': config.USER_AGENT, 'Content-Type': 'application/json;charset=UTF-8', } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8')) return ReturnValue(rawResponse=r)
def set_pinned(self, userName, isPinned=True): url = '%s/webwxoplog?pass_ticket=%s' % (self.loginInfo['url'], self.loginInfo['pass_ticket']) data = { 'UserName': userName, 'CmdId': 3, 'OP': int(isPinned), 'BaseRequest': self.loginInfo['BaseRequest'], } headers = {'User-Agent': config.USER_AGENT} r = self.s.post(url, json=data, headers=headers) return ReturnValue(rawResponse=r)
def revoke(self, msgId, toUserName, localId=None): url = '%s/webwxrevokemsg' % self.loginInfo['url'] data = { 'BaseRequest': self.loginInfo['BaseRequest'], "ClientMsgId": localId or str(time.time() * 1e3), "SvrMsgId": msgId, "ToUserName": toUserName} headers = { 'ContentType': 'application/json; charset=UTF-8', 'User-Agent' : config.USER_AGENT } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8')) return ReturnValue(rawResponse=r)
def send_file(self, fileDir, toUserName=None, mediaId=None, file_=None): logger.debug('Request to send a file(mediaId: %s) to %s: %s' % ( mediaId, toUserName, fileDir)) if hasattr(fileDir, 'read'): return ReturnValue({'BaseResponse': { 'ErrMsg': 'fileDir param should not be an opened file in send_file', 'Ret': -1005, }}) if toUserName is None: toUserName = self.storageClass.userName preparedFile = _prepare_file(fileDir, file_) if not preparedFile: return preparedFile fileSize = preparedFile['fileSize'] if mediaId is None: r = self.upload_file(fileDir, preparedFile=preparedFile) if r: mediaId = r['MediaId'] else: return r url = '%s/webwxsendappmsg?fun=async&f=json' % self.loginInfo['url'] data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Msg': { 'Type': 6, 'Content': ("<appmsg appid='wxeb7ec651dd0aefa9' sdkver=''><title>%s</title>" % os.path.basename(fileDir) + "<des></des><action></action><type>6</type><content></content><url></url><lowurl></lowurl>" + "<appattach><totallen>%s</totallen><attachid>%s</attachid>" % (str(fileSize), mediaId) + "<fileext>%s</fileext></appattach><extinfo></extinfo></appmsg>" % os.path.splitext(fileDir)[1].replace('.','')), 'FromUserName': self.storageClass.userName, 'ToUserName': toUserName, 'LocalID': int(time.time() * 1e4), 'ClientMsgId': int(time.time() * 1e4), }, 'Scene': 0, } headers = { 'User-Agent': config.USER_AGENT, 'Content-Type': 'application/json;charset=UTF-8', } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8')) return ReturnValue(rawResponse=r)
def send_video(self, fileDir=None, toUserName=None, mediaId=None, file_=None): logger.debug('Request to send a video(mediaId: %s) to %s: %s' % ( mediaId, toUserName, fileDir)) if fileDir or file_: if hasattr(fileDir, 'read'): file_, fileDir = fileDir, None if fileDir is None: fileDir = 'tmp.mp4' # specific fileDir to send other formats else: return ReturnValue({'BaseResponse': { 'ErrMsg': 'Either fileDir or file_ should be specific', 'Ret': -1005, }}) if toUserName is None: toUserName = self.storageClass.userName if mediaId is None: r = self.upload_file(fileDir, isVideo=True, file_=file_) if r: mediaId = r['MediaId'] else: return r url = '%s/webwxsendvideomsg?fun=async&f=json&pass_ticket=%s' % ( self.loginInfo['url'], self.loginInfo['pass_ticket']) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Msg': { 'Type' : 43, 'MediaId' : mediaId, 'FromUserName' : self.storageClass.userName, 'ToUserName' : toUserName, 'LocalID' : int(time.time() * 1e4), 'ClientMsgId' : int(time.time() * 1e4), }, 'Scene': 0, } headers = { 'User-Agent' : config.USER_AGENT, 'Content-Type': 'application/json;charset=UTF-8', } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8')) return ReturnValue(rawResponse=r)
def set_alias(self, userName, alias): oldFriendInfo = utils.search_dict_list(self.memberList, 'UserName', userName) if oldFriendInfo is None: return ReturnValue({'BaseResponse': { 'Ret': -1001, }}) url = '%s/webwxoplog?lang=%s&pass_ticket=%s' % ( self.loginInfo['url'], 'zh_CN', self.loginInfo['pass_ticket']) data = { 'UserName': userName, 'CmdId': 2, 'RemarkName': alias, 'BaseRequest': self.loginInfo['BaseRequest'], } headers = {'User-Agent': config.USER_AGENT} r = self.s.post(url, json.dumps(data, ensure_ascii=False).encode('utf8'), headers=headers) r = ReturnValue(rawResponse=r) if r: oldFriendInfo['RemarkName'] = alias return r
def delete_member_from_chatroom(self, chatroomUserName, memberList): url = '%s/webwxupdatechatroom?fun=delmember&pass_ticket=%s' % ( self.loginInfo['url'], self.loginInfo['pass_ticket']) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'ChatRoomName': chatroomUserName, 'DelMemberList': ','.join([member['UserName'] for member in memberList]), } headers = { 'content-type': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT } r = self.s.post(url, data=json.dumps(data), headers=headers) return ReturnValue(rawResponse=r)
def show_mobile_login(self): url = '%s/webwxstatusnotify?lang=zh_CN&pass_ticket=%s' % ( self.loginInfo['url'], self.loginInfo['pass_ticket']) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Code': 3, 'FromUserName': self.storageClass.userName, 'ToUserName': self.storageClass.userName, 'ClientMsgId': int(time.time()), } headers = { 'ContentType': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT, } r = self.s.post(url, data=json.dumps(data), headers=headers) return ReturnValue(rawResponse=r)
def set_chatroom_name(self, chatroomUserName, name): url = '%s/webwxupdatechatroom?fun=modtopic&pass_ticket=%s' % ( self.loginInfo['url'], self.loginInfo['pass_ticket']) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'ChatRoomName': chatroomUserName, 'NewTopic': name, } headers = { 'content-type': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode( 'utf8', 'ignore')) return ReturnValue(rawResponse=r)
def download_video(videoDir=None): url = '%s/webwxgetvideo' % core.loginInfo['url'] params = { 'msgid': msgId, 'skey': core.loginInfo['skey'],} headers = {'Range': 'bytes=0-', 'User-Agent' : config.USER_AGENT } r = core.s.get(url, params=params, headers=headers, stream=True) tempStorage = io.BytesIO() for block in r.iter_content(1024): tempStorage.write(block) if videoDir is None: return tempStorage.getvalue() with open(videoDir, 'wb') as f: f.write(tempStorage.getvalue()) return ReturnValue({'BaseResponse': { 'ErrMsg': 'Successfully downloaded', 'Ret': 0, }})
def download_fn(downloadDir=None): params = { 'msgid': msgId, 'skey': core.loginInfo['skey'],} headers = { 'User-Agent' : config.USER_AGENT } r = core.s.get(url, params=params, stream=True, headers = headers) tempStorage = io.BytesIO() for block in r.iter_content(1024): tempStorage.write(block) if downloadDir is None: return tempStorage.getvalue() with open(downloadDir, 'wb') as f: f.write(tempStorage.getvalue()) tempStorage.seek(0) return ReturnValue({'BaseResponse': { 'ErrMsg': 'Successfully downloaded', 'Ret': 0, }, 'PostFix': utils.get_image_postfix(tempStorage.read(20)), })
def send_raw_msg(self, msgType, content, toUserName): # print self.loginInfo url = '%s/webwxsendmsg' % self.loginInfo['url'] data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'Msg': { 'Type': msgType, 'Content': content, 'FromUserName': self.storageClass.userName, 'ToUserName': (toUserName if toUserName else self.storageClass.userName), 'LocalID': int(time.time() * 1e4), 'ClientMsgId': int(time.time() * 1e4), }, 'Scene': 0, } headers = { 'ContentType': 'application/json; charset=UTF-8', 'User-Agent' : config.USER_AGENT } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8')) return ReturnValue(rawResponse=r)
def create_chatroom(self, memberList, topic=''): url = '%s/webwxcreatechatroom?pass_ticket=%s&r=%s' % ( self.loginInfo['url'], self.loginInfo['pass_ticket'], int(time.time())) data = { 'BaseRequest': self.loginInfo['BaseRequest'], 'MemberCount': len(memberList), 'MemberList': [{ 'UserName': member['UserName'] } for member in memberList], 'Topic': topic, } headers = { 'content-type': 'application/json; charset=UTF-8', 'User-Agent': config.USER_AGENT } r = self.s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode( 'utf8', 'ignore')) return ReturnValue(rawResponse=r)
def logout(self): if self.alive: url = '%s/webwxlogout' % self.loginInfo['url'] params = { 'redirect': 1, 'type': 1, 'skey': self.loginInfo['skey'], } headers = {'User-Agent': config.USER_AGENT} self.s.get(url, params=params, headers=headers) self.alive = False self.isLogging = False self.s.cookies.clear() del self.chatroomList[:] del self.memberList[:] del self.mpList[:] return ReturnValue( {'BaseResponse': { 'ErrMsg': 'logout successfully.', 'Ret': 0, }})
def download_atta(attaDir=None): url = core.loginInfo['fileUrl'] + '/webwxgetmedia' params = { 'sender': rawMsg['FromUserName'], 'mediaid': rawMsg['MediaId'], 'filename': rawMsg['FileName'], 'fromuser': core.loginInfo['wxuin'], 'pass_ticket': 'undefined', 'webwx_data_ticket': cookiesList['webwx_data_ticket'],} headers = { 'User-Agent' : config.USER_AGENT } r = core.s.get(url, params=params, stream=True, headers=headers) tempStorage = io.BytesIO() for block in r.iter_content(1024): tempStorage.write(block) if attaDir is None: return tempStorage.getvalue() with open(attaDir, 'wb') as f: f.write(tempStorage.getvalue()) return ReturnValue({'BaseResponse': { 'ErrMsg': 'Successfully downloaded', 'Ret': 0, }})
def update(self): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not be updated' % \ self.__class__.__name__, }, })
def send(self, msg, mediaId=None): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not send message directly' % \ self.__class__.__name__, }, })
def send_msg(self, msg='Test Message'): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not send message directly' % \ self.__class__.__name__, }, })
def send_raw_msg(self, msgType, content): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not send message directly' % \ self.__class__.__name__, }, })
def add_member(self, userName): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not add member' % \ self.__class__.__name__, }, })
def verify(self): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s do not need verify' % \ self.__class__.__name__, }, })
def set_pinned(self, isPinned=True): return ReturnValue({'BaseResponse': { 'Ret': -1006, 'ErrMsg': '%s can not be pinned' % \ self.__class__.__name__, }, })